• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2020 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 package com.android.systemui.biometrics
17 
18 import android.content.Context
19 import android.graphics.Canvas
20 import android.graphics.Color
21 import android.graphics.Paint
22 import android.graphics.PointF
23 import android.graphics.Rect
24 import android.graphics.RectF
25 import android.util.AttributeSet
26 import android.util.Log
27 import android.view.MotionEvent
28 import android.widget.FrameLayout
29 import com.android.systemui.R
30 import com.android.systemui.doze.DozeReceiver
31 
32 private const val TAG = "UdfpsView"
33 
34 /**
35  * The main view group containing all UDFPS animations.
36  */
37 class UdfpsView(
38     context: Context,
39     attrs: AttributeSet?
40 ) : FrameLayout(context, attrs), DozeReceiver {
41 
42     // Use expanded overlay when feature flag is true, set by UdfpsViewController
43     var useExpandedOverlay: Boolean = false
44 
45     // sensorRect may be bigger than the sensor. True sensor dimensions are defined in
46     // overlayParams.sensorBounds
47     var sensorRect = Rect()
48     private var mUdfpsDisplayMode: UdfpsDisplayModeProvider? = null
49     private val debugTextPaint = Paint().apply {
50         isAntiAlias = true
51         color = Color.BLUE
52         textSize = 32f
53     }
54 
55     private val sensorTouchAreaCoefficient: Float =
56         context.theme.obtainStyledAttributes(attrs, R.styleable.UdfpsView, 0, 0).use { a ->
57             require(a.hasValue(R.styleable.UdfpsView_sensorTouchAreaCoefficient)) {
58                 "UdfpsView must contain sensorTouchAreaCoefficient"
59             }
60             a.getFloat(R.styleable.UdfpsView_sensorTouchAreaCoefficient, 0f)
61         }
62 
63     /** View controller (can be different for enrollment, BiometricPrompt, Keyguard, etc.). */
64     var animationViewController: UdfpsAnimationViewController<*>? = null
65 
66     /** Parameters that affect the position and size of the overlay. */
67     var overlayParams = UdfpsOverlayParams()
68 
69     /** Debug message. */
70     var debugMessage: String? = null
71         set(value) {
72             field = value
73             postInvalidate()
74         }
75 
76     /** True after the call to [configureDisplay] and before the call to [unconfigureDisplay]. */
77     var isDisplayConfigured: Boolean = false
78         private set
79 
80     fun setUdfpsDisplayModeProvider(udfpsDisplayModeProvider: UdfpsDisplayModeProvider?) {
81         mUdfpsDisplayMode = udfpsDisplayModeProvider
82     }
83 
84     // Don't propagate any touch events to the child views.
85     override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
86         return (animationViewController == null || !animationViewController!!.shouldPauseAuth())
87     }
88 
89     override fun dozeTimeTick() {
90         animationViewController?.dozeTimeTick()
91     }
92 
93     override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
94         super.onLayout(changed, left, top, right, bottom)
95 
96         val paddingX = animationViewController?.paddingX ?: 0
97         val paddingY = animationViewController?.paddingY ?: 0
98 
99         // Updates sensor rect in relation to the overlay view
100         if (useExpandedOverlay) {
101             animationViewController?.onSensorRectUpdated(RectF(sensorRect))
102         } else {
103             sensorRect.set(
104                     paddingX,
105                     paddingY,
106                     (overlayParams.sensorBounds.width() + paddingX),
107                     (overlayParams.sensorBounds.height() + paddingY)
108             )
109 
110             animationViewController?.onSensorRectUpdated(RectF(sensorRect))
111         }
112     }
113 
114     override fun onAttachedToWindow() {
115         super.onAttachedToWindow()
116         Log.v(TAG, "onAttachedToWindow")
117     }
118 
119     override fun onDetachedFromWindow() {
120         super.onDetachedFromWindow()
121         Log.v(TAG, "onDetachedFromWindow")
122     }
123 
124     override fun onDraw(canvas: Canvas) {
125         super.onDraw(canvas)
126         if (!isDisplayConfigured) {
127             if (!debugMessage.isNullOrEmpty()) {
128                 canvas.drawText(debugMessage!!, 0f, 160f, debugTextPaint)
129             }
130         }
131     }
132 
133     fun isWithinSensorArea(x: Float, y: Float): Boolean {
134         // The X and Y coordinates of the sensor's center.
135         val translation = animationViewController?.touchTranslation ?: PointF(0f, 0f)
136         val cx = sensorRect.centerX() + translation.x
137         val cy = sensorRect.centerY() + translation.y
138         // Radii along the X and Y axes.
139         val rx = (sensorRect.right - sensorRect.left) / 2.0f
140         val ry = (sensorRect.bottom - sensorRect.top) / 2.0f
141 
142         return x > cx - rx * sensorTouchAreaCoefficient &&
143             x < cx + rx * sensorTouchAreaCoefficient &&
144             y > cy - ry * sensorTouchAreaCoefficient &&
145             y < cy + ry * sensorTouchAreaCoefficient &&
146             !(animationViewController?.shouldPauseAuth() ?: false)
147     }
148 
149     fun configureDisplay(onDisplayConfigured: Runnable) {
150         isDisplayConfigured = true
151         animationViewController?.onDisplayConfiguring()
152         mUdfpsDisplayMode?.enable(onDisplayConfigured)
153     }
154 
155     fun unconfigureDisplay() {
156         isDisplayConfigured = false
157         animationViewController?.onDisplayUnconfigured()
158         mUdfpsDisplayMode?.disable(null /* onDisabled */)
159     }
160 }
161