1 /*
2  * Copyright (C) 2019 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 
20 import android.content.Context;
21 import android.graphics.drawable.AnimatedVectorDrawable;
22 import android.graphics.drawable.Drawable;
23 import android.util.AttributeSet;
24 import android.util.Log;
25 
26 import androidx.annotation.Nullable;
27 
28 import com.android.systemui.R;
29 
30 public class AuthBiometricFingerprintView extends AuthBiometricView {
31 
32     private static final String TAG = "BiometricPrompt/AuthBiometricFingerprintView";
33 
AuthBiometricFingerprintView(Context context)34     public AuthBiometricFingerprintView(Context context) {
35         this(context, null);
36     }
37 
AuthBiometricFingerprintView(Context context, AttributeSet attrs)38     public AuthBiometricFingerprintView(Context context, AttributeSet attrs) {
39         super(context, attrs);
40     }
41 
42     @Override
getDelayAfterAuthenticatedDurationMs()43     protected int getDelayAfterAuthenticatedDurationMs() {
44         return 0;
45     }
46 
47     @Override
getStateForAfterError()48     protected int getStateForAfterError() {
49         return STATE_AUTHENTICATING;
50     }
51 
52     @Override
handleResetAfterError()53     protected void handleResetAfterError() {
54         showTouchSensorString();
55     }
56 
57     @Override
handleResetAfterHelp()58     protected void handleResetAfterHelp() {
59         showTouchSensorString();
60     }
61 
62     @Override
supportsSmallDialog()63     protected boolean supportsSmallDialog() {
64         return false;
65     }
66 
67     @Override
updateState(@iometricState int newState)68     public void updateState(@BiometricState int newState) {
69         updateIcon(mState, newState);
70 
71         // Do this last since the state variable gets updated.
72         super.updateState(newState);
73     }
74 
75     @Override
onAttachedToWindowInternal()76     void onAttachedToWindowInternal() {
77         super.onAttachedToWindowInternal();
78         showTouchSensorString();
79     }
80 
showTouchSensorString()81     private void showTouchSensorString() {
82         mIndicatorView.setText(R.string.fingerprint_dialog_touch_sensor);
83         mIndicatorView.setTextColor(mTextColorHint);
84     }
85 
updateIcon(int lastState, int newState)86     private void updateIcon(int lastState, int newState) {
87         final Drawable icon = getAnimationForTransition(lastState, newState);
88         if (icon == null) {
89             Log.e(TAG, "Animation not found, " + lastState + " -> " + newState);
90             return;
91         }
92 
93         final AnimatedVectorDrawable animation = icon instanceof AnimatedVectorDrawable
94                 ? (AnimatedVectorDrawable) icon
95                 : null;
96 
97         mIconView.setImageDrawable(icon);
98 
99         final CharSequence iconContentDescription = getIconContentDescription(newState);
100         if (iconContentDescription != null) {
101             mIconView.setContentDescription(iconContentDescription);
102         }
103 
104         if (animation != null && shouldAnimateForTransition(lastState, newState)) {
105             animation.forceAnimationOnUI();
106             animation.start();
107         }
108     }
109 
110     @Nullable
getIconContentDescription(int newState)111     private CharSequence getIconContentDescription(int newState) {
112         switch (newState) {
113             case STATE_IDLE:
114             case STATE_AUTHENTICATING_ANIMATING_IN:
115             case STATE_AUTHENTICATING:
116             case STATE_PENDING_CONFIRMATION:
117             case STATE_AUTHENTICATED:
118                 return mContext.getString(
119                         R.string.accessibility_fingerprint_dialog_fingerprint_icon);
120 
121             case STATE_ERROR:
122             case STATE_HELP:
123                 return mContext.getString(R.string.biometric_dialog_try_again);
124 
125             default:
126                 return null;
127         }
128     }
129 
shouldAnimateForTransition(int oldState, int newState)130     private boolean shouldAnimateForTransition(int oldState, int newState) {
131         switch (newState) {
132             case STATE_HELP:
133             case STATE_ERROR:
134                 return true;
135             case STATE_AUTHENTICATING_ANIMATING_IN:
136             case STATE_AUTHENTICATING:
137                 if (oldState == STATE_ERROR || oldState == STATE_HELP) {
138                     return true;
139                 } else {
140                     return false;
141                 }
142             case STATE_AUTHENTICATED:
143                 return false;
144             default:
145                 return false;
146         }
147     }
148 
getAnimationForTransition(int oldState, int newState)149     private Drawable getAnimationForTransition(int oldState, int newState) {
150         int iconRes;
151 
152         switch (newState) {
153             case STATE_HELP:
154             case STATE_ERROR:
155                 iconRes = R.drawable.fingerprint_dialog_fp_to_error;
156                 break;
157             case STATE_AUTHENTICATING_ANIMATING_IN:
158             case STATE_AUTHENTICATING:
159                 if (oldState == STATE_ERROR || oldState == STATE_HELP) {
160                     iconRes = R.drawable.fingerprint_dialog_error_to_fp;
161                 } else {
162                     iconRes = R.drawable.fingerprint_dialog_fp_to_error;
163                 }
164                 break;
165             case STATE_AUTHENTICATED:
166                 iconRes = R.drawable.fingerprint_dialog_fp_to_error;
167                 break;
168             default:
169                 return null;
170         }
171 
172         return mContext.getDrawable(iconRes);
173     }
174 }
175