• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 import android.animation.AnimatorSet;
20 import android.animation.ValueAnimator;
21 import android.annotation.IntDef;
22 import android.content.Context;
23 import android.graphics.Outline;
24 import android.util.Log;
25 import android.view.View;
26 import android.view.ViewOutlineProvider;
27 import android.view.animation.AccelerateDecelerateInterpolator;
28 
29 import com.android.systemui.R;
30 
31 import java.lang.annotation.Retention;
32 import java.lang.annotation.RetentionPolicy;
33 
34 /**
35  * Controls the back panel and its animations for the BiometricPrompt UI.
36  */
37 public class AuthPanelController extends ViewOutlineProvider {
38     public static final int POSITION_BOTTOM = 1;
39     public static final int POSITION_LEFT = 2;
40     public static final int POSITION_RIGHT = 3;
41 
42     @IntDef({POSITION_BOTTOM, POSITION_LEFT, POSITION_RIGHT})
43     @Retention(RetentionPolicy.SOURCE)
44     public @interface Position {}
45 
46     private static final String TAG = "BiometricPrompt/AuthPanelController";
47     private static final boolean DEBUG = false;
48 
49     private final Context mContext;
50     private final View mPanelView;
51 
52     @Position private int mPosition = POSITION_BOTTOM;
53     private boolean mUseFullScreen;
54 
55     private int mContainerWidth;
56     private int mContainerHeight;
57 
58     private int mContentWidth;
59     private int mContentHeight;
60 
61     private float mCornerRadius;
62     private int mMargin;
63 
64     @Override
getOutline(View view, Outline outline)65     public void getOutline(View view, Outline outline) {
66         final int left = getLeftBound(mPosition);
67         final int right = left + mContentWidth;
68 
69         // If the content fits in the container, shrink the height to wrap it. Otherwise, expand to
70         // fill the display (minus the margin), since the content is scrollable.
71         final int top = getTopBound(mPosition);
72         final int bottom = Math.min(top + mContentHeight, mContainerHeight - mMargin);
73 
74         outline.setRoundRect(left, top, right, bottom, mCornerRadius);
75     }
76 
getLeftBound(@osition int position)77     private int getLeftBound(@Position int position) {
78         switch (position) {
79             case POSITION_BOTTOM:
80                 return (mContainerWidth - mContentWidth) / 2;
81             case POSITION_LEFT:
82                 return mMargin;
83             case POSITION_RIGHT:
84                 return mContainerWidth - mContentWidth - mMargin;
85             default:
86                 Log.e(TAG, "Unrecognized position: " + position);
87                 return getLeftBound(POSITION_BOTTOM);
88         }
89     }
90 
getTopBound(@osition int position)91     private int getTopBound(@Position int position) {
92         switch (position) {
93             case POSITION_BOTTOM:
94                 return Math.max(mContainerHeight - mContentHeight - mMargin, mMargin);
95             case POSITION_LEFT:
96             case POSITION_RIGHT:
97                 return Math.max((mContainerHeight - mContentHeight) / 2, mMargin);
98             default:
99                 Log.e(TAG, "Unrecognized position: " + position);
100                 return getTopBound(POSITION_BOTTOM);
101         }
102     }
103 
setContainerDimensions(int containerWidth, int containerHeight)104     public void setContainerDimensions(int containerWidth, int containerHeight) {
105         if (DEBUG) {
106             Log.v(TAG, "Container Width: " + containerWidth + " Height: " + containerHeight);
107         }
108         mContainerWidth = containerWidth;
109         mContainerHeight = containerHeight;
110     }
111 
setPosition(@osition int position)112     public void setPosition(@Position int position) {
113         mPosition = position;
114     }
115 
setUseFullScreen(boolean fullScreen)116     public void setUseFullScreen(boolean fullScreen) {
117         mUseFullScreen = fullScreen;
118     }
119 
getTranslationAnimator(float relativeTranslationY)120     public ValueAnimator getTranslationAnimator(float relativeTranslationY) {
121         final ValueAnimator animator = ValueAnimator.ofFloat(
122                 mPanelView.getY(), mPanelView.getY() - relativeTranslationY);
123         animator.addUpdateListener(animation -> {
124             final float translation = (float) animation.getAnimatedValue();
125             mPanelView.setTranslationY(translation);
126         });
127         return animator;
128     }
129 
getAlphaAnimator(float alpha)130     public ValueAnimator getAlphaAnimator(float alpha) {
131         final ValueAnimator animator = ValueAnimator.ofFloat(mPanelView.getAlpha(), alpha);
132         animator.addUpdateListener(animation -> {
133             mPanelView.setAlpha((float) animation.getAnimatedValue());
134         });
135         return animator;
136     }
137 
updateForContentDimensions(int contentWidth, int contentHeight, int animateDurationMs)138     public void updateForContentDimensions(int contentWidth, int contentHeight,
139             int animateDurationMs) {
140         if (DEBUG) {
141             Log.v(TAG, "Content Width: " + contentWidth
142                     + " Height: " + contentHeight
143                     + " Animate: " + animateDurationMs);
144         }
145 
146         if (mContainerWidth == 0 || mContainerHeight == 0) {
147             Log.w(TAG, "Not done measuring yet");
148             return;
149         }
150 
151         final int margin = mUseFullScreen ? 0 : (int) mContext.getResources()
152                 .getDimension(R.dimen.biometric_dialog_border_padding);
153         final float cornerRadius = mUseFullScreen ? 0 : mContext.getResources()
154                 .getDimension(R.dimen.biometric_dialog_corner_size);
155 
156         if (animateDurationMs > 0) {
157             // Animate margin
158             ValueAnimator marginAnimator = ValueAnimator.ofInt(mMargin, margin);
159             marginAnimator.addUpdateListener((animation) -> {
160                 mMargin = (int) animation.getAnimatedValue();
161             });
162 
163             // Animate corners
164             ValueAnimator cornerAnimator = ValueAnimator.ofFloat(mCornerRadius, cornerRadius);
165             cornerAnimator.addUpdateListener((animation) -> {
166                 mCornerRadius = (float) animation.getAnimatedValue();
167             });
168 
169             // Animate height
170             ValueAnimator heightAnimator = ValueAnimator.ofInt(mContentHeight, contentHeight);
171             heightAnimator.addUpdateListener((animation) -> {
172                 mContentHeight = (int) animation.getAnimatedValue();
173                 mPanelView.invalidateOutline();
174             });
175 
176             // Animate width
177             ValueAnimator widthAnimator = ValueAnimator.ofInt(mContentWidth, contentWidth);
178             widthAnimator.addUpdateListener((animation) -> {
179                 mContentWidth = (int) animation.getAnimatedValue();
180             });
181 
182             // Play together
183             AnimatorSet as = new AnimatorSet();
184             as.setDuration(animateDurationMs);
185             as.setInterpolator(new AccelerateDecelerateInterpolator());
186             as.playTogether(cornerAnimator, heightAnimator, widthAnimator, marginAnimator);
187             as.start();
188 
189         } else {
190             mMargin = margin;
191             mCornerRadius = cornerRadius;
192             mContentWidth = contentWidth;
193             mContentHeight = contentHeight;
194             mPanelView.invalidateOutline();
195         }
196     }
197 
getContainerWidth()198     int getContainerWidth() {
199         return mContainerWidth;
200     }
201 
getContainerHeight()202     int getContainerHeight() {
203         return mContainerHeight;
204     }
205 
AuthPanelController(Context context, View panelView)206     AuthPanelController(Context context, View panelView) {
207         mContext = context;
208         mPanelView = panelView;
209         mCornerRadius = context.getResources()
210                 .getDimension(R.dimen.biometric_dialog_corner_size);
211         mMargin = (int) context.getResources()
212                 .getDimension(R.dimen.biometric_dialog_border_padding);
213         mPanelView.setOutlineProvider(this);
214         mPanelView.setClipToOutline(true);
215     }
216 
217 }
218