1 /* <lambda>null2 * Copyright (C) 2021 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.animation.ValueAnimator 19 import android.graphics.PointF 20 import android.graphics.RectF 21 import com.android.systemui.Dumpable 22 import com.android.systemui.animation.Interpolators 23 import com.android.systemui.dump.DumpManager 24 import com.android.systemui.plugins.statusbar.StatusBarStateController 25 import com.android.systemui.shade.ShadeExpansionListener 26 import com.android.systemui.shade.ShadeExpansionStateManager 27 import com.android.systemui.statusbar.phone.SystemUIDialogManager 28 import com.android.systemui.util.ViewController 29 import java.io.PrintWriter 30 31 /** 32 * Handles: 33 * 1. registering for listeners when its view is attached and unregistering on view detached 34 * 2. pausing UDFPS when FingerprintManager may still be running but we temporarily want to hide 35 * the affordance. this allows us to fade the view in and out nicely (see shouldPauseAuth) 36 * 3. sending events to its view including: 37 * - enabling and disabling of the UDFPS display mode 38 * - sensor position changes 39 * - doze time event 40 */ 41 abstract class UdfpsAnimationViewController<T : UdfpsAnimationView>( 42 view: T, 43 protected val statusBarStateController: StatusBarStateController, 44 protected val shadeExpansionStateManager: ShadeExpansionStateManager, 45 protected val dialogManager: SystemUIDialogManager, 46 private val dumpManager: DumpManager 47 ) : ViewController<T>(view), Dumpable { 48 49 protected abstract val tag: String 50 51 private val view: T 52 get() = mView!! 53 54 private var dialogAlphaAnimator: ValueAnimator? = null 55 private val dialogListener = SystemUIDialogManager.Listener { runDialogAlphaAnimator() } 56 57 private val shadeExpansionListener = ShadeExpansionListener { event -> 58 // Notification shade can be expanded but not visible (fraction: 0.0), for example 59 // when a heads-up notification (HUN) is showing. 60 notificationShadeVisible = event.expanded && event.fraction > 0f 61 view.onExpansionChanged(event.fraction) 62 updatePauseAuth() 63 } 64 65 /** If the notification shade is visible. */ 66 var notificationShadeVisible: Boolean = false 67 68 /** 69 * The amount of translation needed if the view currently requires the user to touch 70 * somewhere other than the exact center of the sensor. For example, this can happen 71 * during guided enrollment. 72 */ 73 open val touchTranslation: PointF = PointF(0f, 0f) 74 75 /** 76 * X-Padding to add to left and right of the sensor rectangle area to increase the size of our 77 * window to draw within. 78 */ 79 open val paddingX: Int = 0 80 81 /** 82 * Y-Padding to add to top and bottom of the sensor rectangle area to increase the size of our 83 * window to draw within. 84 */ 85 open val paddingY: Int = 0 86 87 open fun updateAlpha() { 88 view.updateAlpha() 89 } 90 91 fun runDialogAlphaAnimator() { 92 val hideAffordance = dialogManager.shouldHideAffordance() 93 dialogAlphaAnimator?.cancel() 94 dialogAlphaAnimator = ValueAnimator.ofFloat( 95 view.calculateAlpha() / 255f, 96 if (hideAffordance) 0f else 1f) 97 .apply { 98 duration = if (hideAffordance) 83L else 200L 99 interpolator = if (hideAffordance) Interpolators.LINEAR else Interpolators.ALPHA_IN 100 101 addUpdateListener { animatedValue -> 102 view.setDialogSuggestedAlpha(animatedValue.animatedValue as Float) 103 updateAlpha() 104 updatePauseAuth() 105 } 106 start() 107 } 108 } 109 110 override fun onViewAttached() { 111 shadeExpansionStateManager.addExpansionListener(shadeExpansionListener) 112 dialogManager.registerListener(dialogListener) 113 dumpManager.registerDumpable(dumpTag, this) 114 } 115 116 override fun onViewDetached() { 117 shadeExpansionStateManager.removeExpansionListener(shadeExpansionListener) 118 dialogManager.unregisterListener(dialogListener) 119 dumpManager.unregisterDumpable(dumpTag) 120 } 121 122 /** 123 * in some cases, onViewAttached is called for the newly added view using an instance of 124 * this controller before onViewDetached is called on the previous view, so we must have a 125 * unique [dumpTag] per instance of this class. 126 */ 127 private val dumpTag = "$tag ($this)" 128 129 override fun dump(pw: PrintWriter, args: Array<String>) { 130 pw.println("mNotificationShadeVisible=$notificationShadeVisible") 131 pw.println("shouldPauseAuth()=" + shouldPauseAuth()) 132 pw.println("isPauseAuth=" + view.isPauseAuth) 133 pw.println("dialogSuggestedAlpha=" + view.dialogSuggestedAlpha) 134 } 135 136 /** 137 * Returns true if the fingerprint manager is running, but we want to temporarily pause 138 * authentication. 139 */ 140 open fun shouldPauseAuth(): Boolean { 141 return notificationShadeVisible || dialogManager.shouldHideAffordance() 142 } 143 144 /** 145 * Send pause auth update to our view. 146 */ 147 fun updatePauseAuth() { 148 if (view.setPauseAuth(shouldPauseAuth())) { 149 view.postInvalidate() 150 } 151 } 152 153 /** 154 * Send sensor position change to our view. This rect contains paddingX and paddingY. 155 */ 156 fun onSensorRectUpdated(sensorRect: RectF) { 157 view.onSensorRectUpdated(sensorRect) 158 } 159 160 /** 161 * Send dozeTimeTick to view in case it wants to handle its burn-in offset. 162 */ 163 fun dozeTimeTick() { 164 if (view.dozeTimeTick()) { 165 view.postInvalidate() 166 } 167 } 168 169 /** 170 * The display began transitioning into the UDFPS mode and the fingerprint manager started 171 * authenticating. 172 */ 173 fun onDisplayConfiguring() { 174 view.onDisplayConfiguring() 175 view.postInvalidate() 176 } 177 178 /** 179 * The display transitioned away from the UDFPS mode and the fingerprint manager stopped 180 * authenticating. 181 */ 182 fun onDisplayUnconfigured() { 183 view.onDisplayUnconfigured() 184 view.postInvalidate() 185 } 186 187 /** 188 * Whether to listen for touches outside of the view. 189 */ 190 open fun listenForTouchesOutsideView(): Boolean = false 191 192 /** 193 * Called when a view should announce an accessibility event. 194 */ 195 open fun doAnnounceForAccessibility(str: String) {} 196 } 197