Loading packages/SystemUI/res/values/ids.xml +2 −1 Original line number Diff line number Diff line Loading @@ -262,8 +262,9 @@ <item type="id" name="device_entry_icon_fg" /> <item type="id" name="device_entry_icon_bg" /> <!--Id for the device-entry UDFPS icon that lives in the alternate bouncer. --> <!--Id for the device-entry UDFPS related views that live in the alternate bouncer. --> <item type="id" name="alternate_bouncer_udfps_icon_view" /> <item type="id" name="alternate_bouncer_udfps_accessibility_overlay" /> <!-- Id for the udfps accessibility overlay --> <item type="id" name="udfps_accessibility_overlay" /> Loading packages/SystemUI/src/com/android/systemui/deviceentry/ui/viewmodel/AlternateBouncerUdfpsAccessibilityOverlayViewModel.kt 0 → 100644 +40 −0 Original line number Diff line number Diff line /* * 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.deviceentry.ui.viewmodel import com.android.systemui.accessibility.domain.interactor.AccessibilityInteractor import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf /** Models the UI state for the alternate bouncer UDFPS accessibility overlay */ @ExperimentalCoroutinesApi class AlternateBouncerUdfpsAccessibilityOverlayViewModel @Inject constructor( udfpsOverlayInteractor: UdfpsOverlayInteractor, accessibilityInteractor: AccessibilityInteractor, ) : UdfpsAccessibilityOverlayViewModel( udfpsOverlayInteractor, accessibilityInteractor, ) { /** Overlay is always visible if touch exploration is enabled on the alternate bouncer. */ override fun isVisibleWhenTouchExplorationEnabled(): Flow<Boolean> = flowOf(true) } packages/SystemUI/src/com/android/systemui/deviceentry/ui/viewmodel/DeviceEntryUdfpsAccessibilityOverlayViewModel.kt 0 → 100644 +53 −0 Original line number Diff line number Diff line /* * 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.deviceentry.ui.viewmodel import com.android.systemui.accessibility.domain.interactor.AccessibilityInteractor import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor import com.android.systemui.keyguard.ui.view.DeviceEntryIconView import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryForegroundViewModel import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryIconViewModel import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine /** Models the UI state for the non-alternate bouncer UDFPS accessibility overlay */ @ExperimentalCoroutinesApi class DeviceEntryUdfpsAccessibilityOverlayViewModel @Inject constructor( udfpsOverlayInteractor: UdfpsOverlayInteractor, accessibilityInteractor: AccessibilityInteractor, private val deviceEntryIconViewModel: DeviceEntryIconViewModel, private val deviceEntryFgIconViewModel: DeviceEntryForegroundViewModel, ) : UdfpsAccessibilityOverlayViewModel( udfpsOverlayInteractor, accessibilityInteractor, ) { /** Overlay is only visible if the UDFPS icon is visible on the keyguard. */ override fun isVisibleWhenTouchExplorationEnabled(): Flow<Boolean> = combine( deviceEntryFgIconViewModel.viewModel, deviceEntryIconViewModel.deviceEntryViewAlpha, ) { iconViewModel, alpha -> iconViewModel.type == DeviceEntryIconView.IconType.FINGERPRINT && !iconViewModel.useAodVariant && alpha == 1f } } packages/SystemUI/src/com/android/systemui/deviceentry/ui/viewmodel/UdfpsAccessibilityOverlayViewModel.kt +4 −19 Original line number Diff line number Diff line Loading @@ -23,48 +23,33 @@ import com.android.systemui.accessibility.domain.interactor.AccessibilityInterac import com.android.systemui.biometrics.UdfpsUtils import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams import com.android.systemui.keyguard.ui.view.DeviceEntryIconView import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryForegroundViewModel import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryIconViewModel import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf /** Models the UI state for the UDFPS accessibility overlay */ @ExperimentalCoroutinesApi class UdfpsAccessibilityOverlayViewModel @Inject constructor( abstract class UdfpsAccessibilityOverlayViewModel( udfpsOverlayInteractor: UdfpsOverlayInteractor, accessibilityInteractor: AccessibilityInteractor, deviceEntryIconViewModel: DeviceEntryIconViewModel, deviceEntryFgIconViewModel: DeviceEntryForegroundViewModel, ) { private val udfpsUtils = UdfpsUtils() private val udfpsOverlayParams: StateFlow<UdfpsOverlayParams> = udfpsOverlayInteractor.udfpsOverlayParams /** Overlay is only visible if touch exploration is enabled and UDFPS can be used. */ val visible: Flow<Boolean> = accessibilityInteractor.isTouchExplorationEnabled.flatMapLatest { touchExplorationEnabled -> if (touchExplorationEnabled) { combine( deviceEntryFgIconViewModel.viewModel, deviceEntryIconViewModel.deviceEntryViewAlpha, ) { iconViewModel, alpha -> iconViewModel.type == DeviceEntryIconView.IconType.FINGERPRINT && !iconViewModel.useAodVariant && alpha == 1f } isVisibleWhenTouchExplorationEnabled() } else { flowOf(false) } } abstract fun isVisibleWhenTouchExplorationEnabled(): Flow<Boolean> /** Give directional feedback to help the user authenticate with UDFPS. */ fun onHoverEvent(v: View, event: MotionEvent): Boolean { val overlayParams = udfpsOverlayParams.value Loading packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt +62 −21 Original line number Diff line number Diff line Loading @@ -17,21 +17,24 @@ package com.android.systemui.keyguard.ui.binder import android.view.View import android.view.ViewGroup import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintSet import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle import com.android.systemui.classifier.Classifier import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor import com.android.systemui.keyguard.ui.SwipeUpAnywhereGestureHandler import com.android.systemui.deviceentry.ui.binder.UdfpsAccessibilityOverlayBinder import com.android.systemui.deviceentry.ui.view.UdfpsAccessibilityOverlay import com.android.systemui.deviceentry.ui.viewmodel.AlternateBouncerUdfpsAccessibilityOverlayViewModel import com.android.systemui.keyguard.ui.view.DeviceEntryIconView import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerDependencies import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerUdfpsIconViewModel import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerViewModel import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.plugins.FalsingManager import com.android.systemui.res.R import com.android.systemui.scrim.ScrimView import com.android.systemui.statusbar.gesture.TapGestureDetector import dagger.Lazy import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.launch Loading @@ -47,21 +50,24 @@ object AlternateBouncerViewBinder { @JvmStatic fun bind( view: ConstraintLayout, viewModel: AlternateBouncerViewModel, falsingManager: FalsingManager, swipeUpAnywhereGestureHandler: SwipeUpAnywhereGestureHandler, tapGestureDetector: TapGestureDetector, alternateBouncerUdfpsIconViewModel: AlternateBouncerUdfpsIconViewModel, alternateBouncerDependencies: AlternateBouncerDependencies, ) { if (DeviceEntryUdfpsRefactor.isUnexpectedlyInLegacyMode()) { return } optionallyAddUdfpsView( optionallyAddUdfpsViews( view = view, alternateBouncerUdfpsIconViewModel = alternateBouncerUdfpsIconViewModel, udfpsIconViewModel = alternateBouncerDependencies.udfpsIconViewModel, udfpsA11yOverlayViewModel = alternateBouncerDependencies.udfpsAccessibilityOverlayViewModel, ) val scrim = view.requireViewById(R.id.alternate_bouncer_scrim) as ScrimView val viewModel = alternateBouncerDependencies.viewModel val swipeUpAnywhereGestureHandler = alternateBouncerDependencies.swipeUpAnywhereGestureHandler val falsingManager = alternateBouncerDependencies.falsingManager val tapGestureDetector = alternateBouncerDependencies.tapGestureDetector view.repeatWhenAttached { alternateBouncerViewContainer -> repeatOnLifecycle(Lifecycle.State.STARTED) { scrim.viewAlpha = 0f Loading Loading @@ -102,44 +108,79 @@ object AlternateBouncerViewBinder { } } private fun optionallyAddUdfpsView( private fun optionallyAddUdfpsViews( view: ConstraintLayout, alternateBouncerUdfpsIconViewModel: AlternateBouncerUdfpsIconViewModel, udfpsIconViewModel: AlternateBouncerUdfpsIconViewModel, udfpsA11yOverlayViewModel: Lazy<AlternateBouncerUdfpsAccessibilityOverlayViewModel>, ) { view.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.CREATED) { launch { alternateBouncerUdfpsIconViewModel.iconLocation.collect { iconLocation -> val viewId = R.id.alternate_bouncer_udfps_icon_view var udfpsView = view.getViewById(viewId) udfpsIconViewModel.iconLocation.collect { iconLocation -> // add UDFPS a11y overlay val udfpsA11yOverlayViewId = R.id.alternate_bouncer_udfps_accessibility_overlay var udfpsA11yOverlay = view.getViewById(udfpsA11yOverlayViewId) if (udfpsA11yOverlay == null) { udfpsA11yOverlay = UdfpsAccessibilityOverlay(view.context).apply { id = udfpsA11yOverlayViewId } view.addView(udfpsA11yOverlay) UdfpsAccessibilityOverlayBinder.bind( udfpsA11yOverlay, udfpsA11yOverlayViewModel.get(), ) } // add UDFPS icon view val udfpsViewId = R.id.alternate_bouncer_udfps_icon_view var udfpsView = view.getViewById(udfpsViewId) if (udfpsView == null) { udfpsView = DeviceEntryIconView(view.context, null).apply { id = viewId } DeviceEntryIconView(view.context, null).apply { id = udfpsViewId contentDescription = context.resources.getString( R.string.accessibility_fingerprint_label ) } view.addView(udfpsView) AlternateBouncerUdfpsViewBinder.bind( udfpsView, alternateBouncerUdfpsIconViewModel, udfpsIconViewModel, ) } val constraintSet = ConstraintSet().apply { clone(view) } constraintSet.apply { constrainWidth(viewId, iconLocation.width) constrainHeight(viewId, iconLocation.height) // udfpsView: constrainWidth(udfpsViewId, iconLocation.width) constrainHeight(udfpsViewId, iconLocation.height) connect( viewId, udfpsViewId, ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP, iconLocation.top, ) connect( viewId, udfpsViewId, ConstraintSet.START, ConstraintSet.PARENT_ID, ConstraintSet.START, iconLocation.left ) // udfpsA11yOverlayView: constrainWidth( udfpsA11yOverlayViewId, ViewGroup.LayoutParams.MATCH_PARENT ) constrainHeight( udfpsA11yOverlayViewId, ViewGroup.LayoutParams.MATCH_PARENT ) } constraintSet.applyTo(view) } Loading Loading
packages/SystemUI/res/values/ids.xml +2 −1 Original line number Diff line number Diff line Loading @@ -262,8 +262,9 @@ <item type="id" name="device_entry_icon_fg" /> <item type="id" name="device_entry_icon_bg" /> <!--Id for the device-entry UDFPS icon that lives in the alternate bouncer. --> <!--Id for the device-entry UDFPS related views that live in the alternate bouncer. --> <item type="id" name="alternate_bouncer_udfps_icon_view" /> <item type="id" name="alternate_bouncer_udfps_accessibility_overlay" /> <!-- Id for the udfps accessibility overlay --> <item type="id" name="udfps_accessibility_overlay" /> Loading
packages/SystemUI/src/com/android/systemui/deviceentry/ui/viewmodel/AlternateBouncerUdfpsAccessibilityOverlayViewModel.kt 0 → 100644 +40 −0 Original line number Diff line number Diff line /* * 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.deviceentry.ui.viewmodel import com.android.systemui.accessibility.domain.interactor.AccessibilityInteractor import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flowOf /** Models the UI state for the alternate bouncer UDFPS accessibility overlay */ @ExperimentalCoroutinesApi class AlternateBouncerUdfpsAccessibilityOverlayViewModel @Inject constructor( udfpsOverlayInteractor: UdfpsOverlayInteractor, accessibilityInteractor: AccessibilityInteractor, ) : UdfpsAccessibilityOverlayViewModel( udfpsOverlayInteractor, accessibilityInteractor, ) { /** Overlay is always visible if touch exploration is enabled on the alternate bouncer. */ override fun isVisibleWhenTouchExplorationEnabled(): Flow<Boolean> = flowOf(true) }
packages/SystemUI/src/com/android/systemui/deviceentry/ui/viewmodel/DeviceEntryUdfpsAccessibilityOverlayViewModel.kt 0 → 100644 +53 −0 Original line number Diff line number Diff line /* * 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.deviceentry.ui.viewmodel import com.android.systemui.accessibility.domain.interactor.AccessibilityInteractor import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor import com.android.systemui.keyguard.ui.view.DeviceEntryIconView import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryForegroundViewModel import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryIconViewModel import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine /** Models the UI state for the non-alternate bouncer UDFPS accessibility overlay */ @ExperimentalCoroutinesApi class DeviceEntryUdfpsAccessibilityOverlayViewModel @Inject constructor( udfpsOverlayInteractor: UdfpsOverlayInteractor, accessibilityInteractor: AccessibilityInteractor, private val deviceEntryIconViewModel: DeviceEntryIconViewModel, private val deviceEntryFgIconViewModel: DeviceEntryForegroundViewModel, ) : UdfpsAccessibilityOverlayViewModel( udfpsOverlayInteractor, accessibilityInteractor, ) { /** Overlay is only visible if the UDFPS icon is visible on the keyguard. */ override fun isVisibleWhenTouchExplorationEnabled(): Flow<Boolean> = combine( deviceEntryFgIconViewModel.viewModel, deviceEntryIconViewModel.deviceEntryViewAlpha, ) { iconViewModel, alpha -> iconViewModel.type == DeviceEntryIconView.IconType.FINGERPRINT && !iconViewModel.useAodVariant && alpha == 1f } }
packages/SystemUI/src/com/android/systemui/deviceentry/ui/viewmodel/UdfpsAccessibilityOverlayViewModel.kt +4 −19 Original line number Diff line number Diff line Loading @@ -23,48 +23,33 @@ import com.android.systemui.accessibility.domain.interactor.AccessibilityInterac import com.android.systemui.biometrics.UdfpsUtils import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor import com.android.systemui.biometrics.shared.model.UdfpsOverlayParams import com.android.systemui.keyguard.ui.view.DeviceEntryIconView import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryForegroundViewModel import com.android.systemui.keyguard.ui.viewmodel.DeviceEntryIconViewModel import javax.inject.Inject import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf /** Models the UI state for the UDFPS accessibility overlay */ @ExperimentalCoroutinesApi class UdfpsAccessibilityOverlayViewModel @Inject constructor( abstract class UdfpsAccessibilityOverlayViewModel( udfpsOverlayInteractor: UdfpsOverlayInteractor, accessibilityInteractor: AccessibilityInteractor, deviceEntryIconViewModel: DeviceEntryIconViewModel, deviceEntryFgIconViewModel: DeviceEntryForegroundViewModel, ) { private val udfpsUtils = UdfpsUtils() private val udfpsOverlayParams: StateFlow<UdfpsOverlayParams> = udfpsOverlayInteractor.udfpsOverlayParams /** Overlay is only visible if touch exploration is enabled and UDFPS can be used. */ val visible: Flow<Boolean> = accessibilityInteractor.isTouchExplorationEnabled.flatMapLatest { touchExplorationEnabled -> if (touchExplorationEnabled) { combine( deviceEntryFgIconViewModel.viewModel, deviceEntryIconViewModel.deviceEntryViewAlpha, ) { iconViewModel, alpha -> iconViewModel.type == DeviceEntryIconView.IconType.FINGERPRINT && !iconViewModel.useAodVariant && alpha == 1f } isVisibleWhenTouchExplorationEnabled() } else { flowOf(false) } } abstract fun isVisibleWhenTouchExplorationEnabled(): Flow<Boolean> /** Give directional feedback to help the user authenticate with UDFPS. */ fun onHoverEvent(v: View, event: MotionEvent): Boolean { val overlayParams = udfpsOverlayParams.value Loading
packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinder.kt +62 −21 Original line number Diff line number Diff line Loading @@ -17,21 +17,24 @@ package com.android.systemui.keyguard.ui.binder import android.view.View import android.view.ViewGroup import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintSet import androidx.lifecycle.Lifecycle import androidx.lifecycle.repeatOnLifecycle import com.android.systemui.classifier.Classifier import com.android.systemui.deviceentry.shared.DeviceEntryUdfpsRefactor import com.android.systemui.keyguard.ui.SwipeUpAnywhereGestureHandler import com.android.systemui.deviceentry.ui.binder.UdfpsAccessibilityOverlayBinder import com.android.systemui.deviceentry.ui.view.UdfpsAccessibilityOverlay import com.android.systemui.deviceentry.ui.viewmodel.AlternateBouncerUdfpsAccessibilityOverlayViewModel import com.android.systemui.keyguard.ui.view.DeviceEntryIconView import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerDependencies import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerUdfpsIconViewModel import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerViewModel import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.plugins.FalsingManager import com.android.systemui.res.R import com.android.systemui.scrim.ScrimView import com.android.systemui.statusbar.gesture.TapGestureDetector import dagger.Lazy import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.launch Loading @@ -47,21 +50,24 @@ object AlternateBouncerViewBinder { @JvmStatic fun bind( view: ConstraintLayout, viewModel: AlternateBouncerViewModel, falsingManager: FalsingManager, swipeUpAnywhereGestureHandler: SwipeUpAnywhereGestureHandler, tapGestureDetector: TapGestureDetector, alternateBouncerUdfpsIconViewModel: AlternateBouncerUdfpsIconViewModel, alternateBouncerDependencies: AlternateBouncerDependencies, ) { if (DeviceEntryUdfpsRefactor.isUnexpectedlyInLegacyMode()) { return } optionallyAddUdfpsView( optionallyAddUdfpsViews( view = view, alternateBouncerUdfpsIconViewModel = alternateBouncerUdfpsIconViewModel, udfpsIconViewModel = alternateBouncerDependencies.udfpsIconViewModel, udfpsA11yOverlayViewModel = alternateBouncerDependencies.udfpsAccessibilityOverlayViewModel, ) val scrim = view.requireViewById(R.id.alternate_bouncer_scrim) as ScrimView val viewModel = alternateBouncerDependencies.viewModel val swipeUpAnywhereGestureHandler = alternateBouncerDependencies.swipeUpAnywhereGestureHandler val falsingManager = alternateBouncerDependencies.falsingManager val tapGestureDetector = alternateBouncerDependencies.tapGestureDetector view.repeatWhenAttached { alternateBouncerViewContainer -> repeatOnLifecycle(Lifecycle.State.STARTED) { scrim.viewAlpha = 0f Loading Loading @@ -102,44 +108,79 @@ object AlternateBouncerViewBinder { } } private fun optionallyAddUdfpsView( private fun optionallyAddUdfpsViews( view: ConstraintLayout, alternateBouncerUdfpsIconViewModel: AlternateBouncerUdfpsIconViewModel, udfpsIconViewModel: AlternateBouncerUdfpsIconViewModel, udfpsA11yOverlayViewModel: Lazy<AlternateBouncerUdfpsAccessibilityOverlayViewModel>, ) { view.repeatWhenAttached { repeatOnLifecycle(Lifecycle.State.CREATED) { launch { alternateBouncerUdfpsIconViewModel.iconLocation.collect { iconLocation -> val viewId = R.id.alternate_bouncer_udfps_icon_view var udfpsView = view.getViewById(viewId) udfpsIconViewModel.iconLocation.collect { iconLocation -> // add UDFPS a11y overlay val udfpsA11yOverlayViewId = R.id.alternate_bouncer_udfps_accessibility_overlay var udfpsA11yOverlay = view.getViewById(udfpsA11yOverlayViewId) if (udfpsA11yOverlay == null) { udfpsA11yOverlay = UdfpsAccessibilityOverlay(view.context).apply { id = udfpsA11yOverlayViewId } view.addView(udfpsA11yOverlay) UdfpsAccessibilityOverlayBinder.bind( udfpsA11yOverlay, udfpsA11yOverlayViewModel.get(), ) } // add UDFPS icon view val udfpsViewId = R.id.alternate_bouncer_udfps_icon_view var udfpsView = view.getViewById(udfpsViewId) if (udfpsView == null) { udfpsView = DeviceEntryIconView(view.context, null).apply { id = viewId } DeviceEntryIconView(view.context, null).apply { id = udfpsViewId contentDescription = context.resources.getString( R.string.accessibility_fingerprint_label ) } view.addView(udfpsView) AlternateBouncerUdfpsViewBinder.bind( udfpsView, alternateBouncerUdfpsIconViewModel, udfpsIconViewModel, ) } val constraintSet = ConstraintSet().apply { clone(view) } constraintSet.apply { constrainWidth(viewId, iconLocation.width) constrainHeight(viewId, iconLocation.height) // udfpsView: constrainWidth(udfpsViewId, iconLocation.width) constrainHeight(udfpsViewId, iconLocation.height) connect( viewId, udfpsViewId, ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP, iconLocation.top, ) connect( viewId, udfpsViewId, ConstraintSet.START, ConstraintSet.PARENT_ID, ConstraintSet.START, iconLocation.left ) // udfpsA11yOverlayView: constrainWidth( udfpsA11yOverlayViewId, ViewGroup.LayoutParams.MATCH_PARENT ) constrainHeight( udfpsA11yOverlayViewId, ViewGroup.LayoutParams.MATCH_PARENT ) } constraintSet.applyTo(view) } Loading