1 /* 2 * 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 17 package com.android.systemui.biometrics; 18 19 import android.annotation.NonNull; 20 import android.graphics.PointF; 21 import android.graphics.RectF; 22 23 import com.android.systemui.Dumpable; 24 import com.android.systemui.dump.DumpManager; 25 import com.android.systemui.plugins.statusbar.StatusBarStateController; 26 import com.android.systemui.statusbar.phone.SystemUIDialogManager; 27 import com.android.systemui.statusbar.phone.panelstate.PanelExpansionListener; 28 import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager; 29 import com.android.systemui.util.ViewController; 30 31 import java.io.FileDescriptor; 32 import java.io.PrintWriter; 33 34 /** 35 * Handles: 36 * 1. registering for listeners when its view is attached and unregistering on view detached 37 * 2. pausing udfps when fingerprintManager may still be running but we temporarily want to hide 38 * the affordance. this allows us to fade the view in and out nicely (see shouldPauseAuth) 39 * 3. sending events to its view including: 40 * - illumination events 41 * - sensor position changes 42 * - doze time event 43 */ 44 abstract class UdfpsAnimationViewController<T extends UdfpsAnimationView> 45 extends ViewController<T> implements Dumpable { 46 @NonNull final StatusBarStateController mStatusBarStateController; 47 @NonNull final PanelExpansionStateManager mPanelExpansionStateManager; 48 @NonNull final SystemUIDialogManager mDialogManager; 49 @NonNull final DumpManager mDumpManger; 50 51 boolean mNotificationShadeVisible; 52 UdfpsAnimationViewController( T view, @NonNull StatusBarStateController statusBarStateController, @NonNull PanelExpansionStateManager panelExpansionStateManager, @NonNull SystemUIDialogManager dialogManager, @NonNull DumpManager dumpManager)53 protected UdfpsAnimationViewController( 54 T view, 55 @NonNull StatusBarStateController statusBarStateController, 56 @NonNull PanelExpansionStateManager panelExpansionStateManager, 57 @NonNull SystemUIDialogManager dialogManager, 58 @NonNull DumpManager dumpManager) { 59 super(view); 60 mStatusBarStateController = statusBarStateController; 61 mPanelExpansionStateManager = panelExpansionStateManager; 62 mDialogManager = dialogManager; 63 mDumpManger = dumpManager; 64 } 65 getTag()66 abstract @NonNull String getTag(); 67 68 @Override onViewAttached()69 protected void onViewAttached() { 70 mPanelExpansionStateManager.addExpansionListener(mPanelExpansionListener); 71 mDialogManager.registerListener(mDialogListener); 72 mDumpManger.registerDumpable(getDumpTag(), this); 73 } 74 75 @Override onViewDetached()76 protected void onViewDetached() { 77 mPanelExpansionStateManager.removeExpansionListener(mPanelExpansionListener); 78 mDialogManager.unregisterListener(mDialogListener); 79 mDumpManger.unregisterDumpable(getDumpTag()); 80 } 81 82 /** 83 * in some cases, onViewAttached is called for the newly added view using an instance of 84 * this controller before onViewDetached is called on the previous view, so we must have a 85 * unique dump tag per instance of this class 86 * @return a unique tag for this instance of this class 87 */ getDumpTag()88 private String getDumpTag() { 89 return getTag() + " (" + this + ")"; 90 } 91 92 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)93 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 94 pw.println("mNotificationShadeVisible=" + mNotificationShadeVisible); 95 pw.println("shouldPauseAuth()=" + shouldPauseAuth()); 96 pw.println("isPauseAuth=" + mView.isPauseAuth()); 97 } 98 99 /** 100 * Returns true if the fingerprint manager is running but we want to temporarily pause 101 * authentication. 102 */ shouldPauseAuth()103 boolean shouldPauseAuth() { 104 return mNotificationShadeVisible 105 || mDialogManager.shouldHideAffordance(); 106 } 107 108 /** 109 * Send pause auth update to our view. 110 */ updatePauseAuth()111 void updatePauseAuth() { 112 if (mView.setPauseAuth(shouldPauseAuth())) { 113 mView.postInvalidate(); 114 } 115 } 116 117 /** 118 * Send sensor position change to our view. This rect contains paddingX and paddingY. 119 */ onSensorRectUpdated(RectF sensorRect)120 void onSensorRectUpdated(RectF sensorRect) { 121 mView.onSensorRectUpdated(sensorRect); 122 } 123 124 /** 125 * Send dozeTimeTick to view in case it wants to handle its burn-in offset. 126 */ dozeTimeTick()127 void dozeTimeTick() { 128 if (mView.dozeTimeTick()) { 129 mView.postInvalidate(); 130 } 131 } 132 133 /** 134 * @return the amount of translation needed if the view currently requires the user to touch 135 * somewhere other than the exact center of the sensor. For example, this can happen 136 * during guided enrollment. 137 */ getTouchTranslation()138 PointF getTouchTranslation() { 139 return new PointF(0, 0); 140 } 141 142 /** 143 * X-Padding to add to left and right of the sensor rectangle area to increase the size of our 144 * window to draw within. 145 * @return 146 */ getPaddingX()147 int getPaddingX() { 148 return 0; 149 } 150 151 /** 152 * Y-Padding to add to top and bottom of the sensor rectangle area to increase the size of our 153 * window to draw within. 154 */ getPaddingY()155 int getPaddingY() { 156 return 0; 157 } 158 159 /** 160 * Udfps has started illuminating and the fingerprint manager is working on authenticating. 161 */ onIlluminationStarting()162 void onIlluminationStarting() { 163 mView.onIlluminationStarting(); 164 mView.postInvalidate(); 165 } 166 167 /** 168 * Udfps has stopped illuminating and the fingerprint manager is no longer attempting to 169 * authenticate. 170 */ onIlluminationStopped()171 void onIlluminationStopped() { 172 mView.onIlluminationStopped(); 173 mView.postInvalidate(); 174 } 175 176 /** 177 * Whether to listen for touches outside of the view. 178 */ listenForTouchesOutsideView()179 boolean listenForTouchesOutsideView() { 180 return false; 181 } 182 183 /** 184 * Called on touches outside of the view if listenForTouchesOutsideView returns true 185 */ onTouchOutsideView()186 void onTouchOutsideView() { } 187 188 private final PanelExpansionListener mPanelExpansionListener = new PanelExpansionListener() { 189 @Override 190 public void onPanelExpansionChanged( 191 float fraction, boolean expanded, boolean tracking) { 192 // Notification shade can be expanded but not visible (fraction: 0.0), for example 193 // when a heads-up notification (HUN) is showing. 194 mNotificationShadeVisible = expanded && fraction > 0f; 195 mView.onExpansionChanged(fraction); 196 updatePauseAuth(); 197 } 198 }; 199 200 private final SystemUIDialogManager.Listener mDialogListener = 201 (shouldHide) -> updatePauseAuth(); 202 } 203