• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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.settings.biometrics.face;
18 
19 import android.animation.TimeAnimator;
20 import android.content.Context;
21 import android.graphics.Canvas;
22 import android.graphics.Color;
23 import android.graphics.ColorFilter;
24 import android.graphics.Paint;
25 import android.graphics.PixelFormat;
26 import android.graphics.PorterDuff;
27 import android.graphics.PorterDuffXfermode;
28 import android.graphics.Rect;
29 import android.graphics.drawable.Drawable;
30 
31 import com.android.settings.biometrics.BiometricEnrollSidecar;
32 
33 /**
34  * A drawable containing the circle cutout as well as the animations.
35  */
36 public class FaceEnrollAnimationDrawable extends Drawable
37         implements BiometricEnrollSidecar.Listener {
38 
39     // Tune this parameter so the UI looks nice - and so that we don't have to draw the animations
40     // outside our bounds. A fraction of each rotating dot should be overlapping the camera preview.
41     private static final int BORDER_BOUNDS = 20;
42 
43     private final Context mContext;
44     private final ParticleCollection.Listener mListener;
45     private Rect mBounds;
46     private final Paint mSquarePaint;
47     private final Paint mCircleCutoutPaint;
48 
49     private ParticleCollection mParticleCollection;
50 
51     private TimeAnimator mTimeAnimator;
52 
53     private final ParticleCollection.Listener mAnimationListener
54             = new ParticleCollection.Listener() {
55         @Override
56         public void onEnrolled() {
57             if (mTimeAnimator != null && mTimeAnimator.isStarted()) {
58                 mTimeAnimator.end();
59                 mListener.onEnrolled();
60             }
61         }
62     };
63 
FaceEnrollAnimationDrawable(Context context, ParticleCollection.Listener listener)64     public FaceEnrollAnimationDrawable(Context context, ParticleCollection.Listener listener) {
65         mContext = context;
66         mListener = listener;
67 
68         mSquarePaint = new Paint();
69         mSquarePaint.setColor(Color.WHITE);
70         mSquarePaint.setAntiAlias(true);
71 
72         mCircleCutoutPaint = new Paint();
73         mCircleCutoutPaint.setColor(Color.TRANSPARENT);
74         mCircleCutoutPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
75         mCircleCutoutPaint.setAntiAlias(true);
76     }
77 
78     @Override
onEnrollmentHelp(int helpMsgId, CharSequence helpString)79     public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) {
80         mParticleCollection.onEnrollmentHelp(helpMsgId, helpString);
81     }
82 
83     @Override
onEnrollmentError(int errMsgId, CharSequence errString)84     public void onEnrollmentError(int errMsgId, CharSequence errString) {
85         mParticleCollection.onEnrollmentError(errMsgId, errString);
86     }
87 
88     @Override
onEnrollmentProgressChange(int steps, int remaining)89     public void onEnrollmentProgressChange(int steps, int remaining) {
90         mParticleCollection.onEnrollmentProgressChange(steps, remaining);
91     }
92 
93     @Override
onBoundsChange(Rect bounds)94     protected void onBoundsChange(Rect bounds) {
95         mBounds = bounds;
96         mParticleCollection =
97                 new ParticleCollection(mContext, mAnimationListener, bounds, BORDER_BOUNDS);
98 
99         if (mTimeAnimator == null) {
100             mTimeAnimator = new TimeAnimator();
101             mTimeAnimator.setTimeListener((animation, totalTimeMs, deltaTimeMs) -> {
102                 mParticleCollection.update(totalTimeMs, deltaTimeMs);
103                 FaceEnrollAnimationDrawable.this.invalidateSelf();
104             });
105             mTimeAnimator.start();
106         }
107     }
108 
109     @Override
draw(Canvas canvas)110     public void draw(Canvas canvas) {
111         if (mBounds == null) {
112             return;
113         }
114         canvas.save();
115 
116         // Draw a rectangle covering the whole view
117         canvas.drawRect(0, 0, mBounds.width(), mBounds.height(), mSquarePaint);
118 
119         // Clear a circle in the middle for the camera preview
120         canvas.drawCircle(mBounds.exactCenterX(), mBounds.exactCenterY(),
121                 mBounds.height() / 2 - BORDER_BOUNDS, mCircleCutoutPaint);
122 
123         // Draw the animation
124         mParticleCollection.draw(canvas);
125 
126         canvas.restore();
127     }
128 
129     @Override
setAlpha(int alpha)130     public void setAlpha(int alpha) {
131 
132     }
133 
134     @Override
setColorFilter(ColorFilter colorFilter)135     public void setColorFilter(ColorFilter colorFilter) {
136 
137     }
138 
139     @Override
getOpacity()140     public int getOpacity() {
141         return PixelFormat.TRANSLUCENT;
142     }
143 }
144