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