• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
20 import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInProgressOffset;
21 
22 import android.animation.Animator;
23 import android.animation.AnimatorListenerAdapter;
24 import android.animation.AnimatorSet;
25 import android.animation.ObjectAnimator;
26 import android.content.Context;
27 import android.graphics.PorterDuff;
28 import android.graphics.PorterDuffColorFilter;
29 import android.util.AttributeSet;
30 import android.util.MathUtils;
31 import android.view.View;
32 import android.widget.ImageView;
33 
34 import androidx.annotation.Nullable;
35 
36 import com.android.settingslib.Utils;
37 import com.android.systemui.R;
38 import com.android.systemui.animation.Interpolators;
39 import com.android.systemui.statusbar.StatusBarState;
40 
41 import com.airbnb.lottie.LottieAnimationView;
42 import com.airbnb.lottie.LottieProperty;
43 import com.airbnb.lottie.model.KeyPath;
44 
45 /**
46  * View corresponding with udfps_keyguard_view.xml
47  */
48 public class UdfpsKeyguardView extends UdfpsAnimationView {
49     private UdfpsDrawable mFingerprintDrawable; // placeholder
50     private LottieAnimationView mAodFp;
51     private LottieAnimationView mLockScreenFp;
52     private int mStatusBarState;
53 
54     // used when highlighting fp icon:
55     private int mTextColorPrimary;
56     private ImageView mBgProtection;
57     boolean mUdfpsRequested;
58 
59     private AnimatorSet mBackgroundInAnimator = new AnimatorSet();
60     private int mAlpha; // 0-255
61 
62     // AOD anti-burn-in offsets
63     private final int mMaxBurnInOffsetX;
64     private final int mMaxBurnInOffsetY;
65     private float mBurnInOffsetX;
66     private float mBurnInOffsetY;
67     private float mBurnInProgress;
68     private float mInterpolatedDarkAmount;
69 
UdfpsKeyguardView(Context context, @Nullable AttributeSet attrs)70     public UdfpsKeyguardView(Context context, @Nullable AttributeSet attrs) {
71         super(context, attrs);
72         mFingerprintDrawable = new UdfpsFpDrawable(context);
73 
74         mMaxBurnInOffsetX = context.getResources()
75             .getDimensionPixelSize(R.dimen.udfps_burn_in_offset_x);
76         mMaxBurnInOffsetY = context.getResources()
77             .getDimensionPixelSize(R.dimen.udfps_burn_in_offset_y);
78     }
79 
80     @Override
onFinishInflate()81     protected void onFinishInflate() {
82         super.onFinishInflate();
83         mAodFp = findViewById(R.id.udfps_aod_fp);
84         mLockScreenFp = findViewById(R.id.udfps_lockscreen_fp);
85         mBgProtection = findViewById(R.id.udfps_keyguard_fp_bg);
86 
87         updateColor();
88 
89         // requires call to invalidate to update the color
90         mLockScreenFp.addValueCallback(
91                 new KeyPath("**"), LottieProperty.COLOR_FILTER,
92                 frameInfo -> new PorterDuffColorFilter(mTextColorPrimary, PorterDuff.Mode.SRC_ATOP)
93         );
94     }
95 
96     @Override
getDrawable()97     public UdfpsDrawable getDrawable() {
98         return mFingerprintDrawable;
99     }
100 
101     @Override
onIlluminationStarting()102     void onIlluminationStarting() {
103     }
104 
105     @Override
onIlluminationStopped()106     void onIlluminationStopped() {
107     }
108 
109     @Override
dozeTimeTick()110     public boolean dozeTimeTick() {
111         updateBurnInOffsets();
112         return true;
113     }
114 
updateBurnInOffsets()115     private void updateBurnInOffsets() {
116         mBurnInOffsetX = MathUtils.lerp(0f,
117             getBurnInOffset(mMaxBurnInOffsetX * 2, true /* xAxis */)
118                 - mMaxBurnInOffsetX, mInterpolatedDarkAmount);
119         mBurnInOffsetY = MathUtils.lerp(0f,
120             getBurnInOffset(mMaxBurnInOffsetY * 2, false /* xAxis */)
121                 - mMaxBurnInOffsetY, mInterpolatedDarkAmount);
122         mBurnInProgress = MathUtils.lerp(0f, getBurnInProgressOffset(), mInterpolatedDarkAmount);
123 
124         mAodFp.setTranslationX(mBurnInOffsetX);
125         mAodFp.setTranslationY(mBurnInOffsetY);
126         mAodFp.setProgress(mBurnInProgress);
127         mAodFp.setAlpha(255 * mInterpolatedDarkAmount);
128 
129         mLockScreenFp.setTranslationX(mBurnInOffsetX);
130         mLockScreenFp.setTranslationY(mBurnInOffsetY);
131         mLockScreenFp.setProgress(1f - mInterpolatedDarkAmount);
132         mLockScreenFp.setAlpha((1f - mInterpolatedDarkAmount) * 255);
133     }
134 
requestUdfps(boolean request, int color)135     void requestUdfps(boolean request, int color) {
136         mUdfpsRequested = request;
137     }
138 
setStatusBarState(int statusBarState)139     void setStatusBarState(int statusBarState) {
140         mStatusBarState = statusBarState;
141     }
142 
updateColor()143     void updateColor() {
144         mTextColorPrimary = Utils.getColorAttrDefaultColor(mContext,
145             android.R.attr.textColorPrimary);
146         mBgProtection.setImageDrawable(getContext().getDrawable(R.drawable.fingerprint_bg));
147         mLockScreenFp.invalidate(); // updated with a valueCallback
148     }
149 
150     /**
151      * @param alpha between 0 and 255
152      */
setUnpausedAlpha(int alpha)153     void setUnpausedAlpha(int alpha) {
154         mAlpha = alpha;
155         updateAlpha();
156     }
157 
158     @Override
updateAlpha()159     protected int updateAlpha() {
160         int alpha = super.updateAlpha();
161         mLockScreenFp.setAlpha(alpha / 255f);
162         if (mInterpolatedDarkAmount != 0f) {
163             mBgProtection.setAlpha(1f - mInterpolatedDarkAmount);
164         } else {
165             mBgProtection.setAlpha(alpha / 255f);
166         }
167 
168         return alpha;
169     }
170 
171     @Override
calculateAlpha()172     int calculateAlpha() {
173         if (mPauseAuth) {
174             return 0;
175         }
176         return mAlpha;
177     }
178 
onDozeAmountChanged(float linear, float eased)179     void onDozeAmountChanged(float linear, float eased) {
180         mInterpolatedDarkAmount = eased;
181         updateAlpha();
182         updateBurnInOffsets();
183     }
184 
185     /**
186      * Animates in the bg protection circle behind the fp icon to highlight the icon.
187      */
animateInUdfpsBouncer(Runnable onEndAnimation)188     void animateInUdfpsBouncer(Runnable onEndAnimation) {
189         if (mBackgroundInAnimator.isRunning()) {
190             // already animating in
191             return;
192         }
193 
194         // fade in and scale up
195         mBackgroundInAnimator = new AnimatorSet();
196         mBackgroundInAnimator.playTogether(
197                 ObjectAnimator.ofFloat(mBgProtection, View.ALPHA, 0f, 1f),
198                 ObjectAnimator.ofFloat(mBgProtection, View.SCALE_X, 0f, 1f),
199                 ObjectAnimator.ofFloat(mBgProtection, View.SCALE_Y, 0f, 1f));
200         mBackgroundInAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
201         mBackgroundInAnimator.setDuration(500);
202         mBackgroundInAnimator.addListener(new AnimatorListenerAdapter() {
203             @Override
204             public void onAnimationEnd(Animator animation) {
205                 if (onEndAnimation != null) {
206                     onEndAnimation.run();
207                 }
208             }
209         });
210         mBackgroundInAnimator.start();
211     }
212 
isShadeLocked()213     private boolean isShadeLocked() {
214         return mStatusBarState == StatusBarState.SHADE_LOCKED;
215     }
216 }
217