1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 package com.android.systemui.keyguard.ui.binder 19 20 import android.graphics.RectF 21 import android.view.View 22 import android.widget.FrameLayout 23 import androidx.asynclayoutinflater.view.AsyncLayoutInflater 24 import androidx.lifecycle.Lifecycle 25 import androidx.lifecycle.repeatOnLifecycle 26 import com.android.systemui.R 27 import com.android.systemui.biometrics.UdfpsKeyguardView 28 import com.android.systemui.biometrics.ui.binder.UdfpsKeyguardInternalViewBinder 29 import com.android.systemui.keyguard.ui.viewmodel.BackgroundViewModel 30 import com.android.systemui.keyguard.ui.viewmodel.FingerprintViewModel 31 import com.android.systemui.keyguard.ui.viewmodel.UdfpsAodViewModel 32 import com.android.systemui.keyguard.ui.viewmodel.UdfpsKeyguardInternalViewModel 33 import com.android.systemui.keyguard.ui.viewmodel.UdfpsKeyguardViewModel 34 import com.android.systemui.lifecycle.repeatWhenAttached 35 import kotlinx.coroutines.ExperimentalCoroutinesApi 36 import kotlinx.coroutines.flow.combine 37 import kotlinx.coroutines.launch 38 39 @ExperimentalCoroutinesApi 40 object UdfpsKeyguardViewBinder { 41 /** 42 * Drives UI for the keyguard UDFPS view. Inflates child views on a background thread. For view 43 * binders for its child views, see [UdfpsFingerprintViewBinder], [UdfpsBackgroundViewBinder] & 44 * [UdfpsAodFingerprintViewBinder]. 45 */ 46 @JvmStatic 47 fun bind( 48 view: UdfpsKeyguardView, 49 viewModel: UdfpsKeyguardViewModel, 50 udfpsKeyguardInternalViewModel: UdfpsKeyguardInternalViewModel, 51 aodViewModel: UdfpsAodViewModel, 52 fingerprintViewModel: FingerprintViewModel, 53 backgroundViewModel: BackgroundViewModel, 54 ) { 55 view.useExpandedOverlay(viewModel.useExpandedOverlay()) 56 57 val layoutInflaterFinishListener = 58 AsyncLayoutInflater.OnInflateFinishedListener { inflatedInternalView, _, parent -> 59 UdfpsKeyguardInternalViewBinder.bind( 60 inflatedInternalView, 61 udfpsKeyguardInternalViewModel, 62 aodViewModel, 63 fingerprintViewModel, 64 backgroundViewModel, 65 ) 66 if (viewModel.useExpandedOverlay()) { 67 val lp = inflatedInternalView.layoutParams as FrameLayout.LayoutParams 68 lp.width = viewModel.sensorBounds.width() 69 lp.height = viewModel.sensorBounds.height() 70 val relativeToView = 71 getBoundsRelativeToView( 72 inflatedInternalView, 73 RectF(viewModel.sensorBounds), 74 ) 75 lp.setMarginsRelative( 76 relativeToView.left.toInt(), 77 relativeToView.top.toInt(), 78 relativeToView.right.toInt(), 79 relativeToView.bottom.toInt(), 80 ) 81 parent!!.addView(inflatedInternalView, lp) 82 } else { 83 parent!!.addView(inflatedInternalView) 84 } 85 } 86 val inflater = AsyncLayoutInflater(view.context) 87 inflater.inflate(R.layout.udfps_keyguard_view_internal, view, layoutInflaterFinishListener) 88 89 view.repeatWhenAttached { 90 repeatOnLifecycle(Lifecycle.State.CREATED) { 91 launch { 92 combine(aodViewModel.isVisible, fingerprintViewModel.visible) { 93 isAodVisible, 94 isFingerprintVisible -> 95 isAodVisible || isFingerprintVisible 96 } 97 .collect { view.setVisible(it) } 98 } 99 } 100 } 101 } 102 103 /** 104 * Converts coordinates of RectF relative to the screen to coordinates relative to this view. 105 * 106 * @param bounds RectF based off screen coordinates in current orientation 107 */ 108 private fun getBoundsRelativeToView(view: View, bounds: RectF): RectF { 109 val pos: IntArray = view.locationOnScreen 110 return RectF( 111 bounds.left - pos[0], 112 bounds.top - pos[1], 113 bounds.right - pos[0], 114 bounds.bottom - pos[1] 115 ) 116 } 117 } 118