• 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 
updateForContentDimensions(int contentWidth, int contentHeight, int animateDurationMs)120     public void updateForContentDimensions(int contentWidth, int contentHeight,
121             int animateDurationMs) {
122         if (DEBUG) {
123             Log.v(TAG, "Content Width: " + contentWidth
124                     + " Height: " + contentHeight
125                     + " Animate: " + animateDurationMs);
126         }
127 
128         if (mContainerWidth == 0 || mContainerHeight == 0) {
129             Log.w(TAG, "Not done measuring yet");
130             return;
131         }
132 
133         final int margin = mUseFullScreen ? 0 : (int) mContext.getResources()
134                 .getDimension(R.dimen.biometric_dialog_border_padding);
135         final float cornerRadius = mUseFullScreen ? 0 : mContext.getResources()
136                 .getDimension(R.dimen.biometric_dialog_corner_size);
137 
138         if (animateDurationMs > 0) {
139             // Animate margin
140             ValueAnimator marginAnimator = ValueAnimator.ofInt(mMargin, margin);
141             marginAnimator.addUpdateListener((animation) -> {
142                 mMargin = (int) animation.getAnimatedValue();
143             });
144 
145             // Animate corners
146             ValueAnimator cornerAnimator = ValueAnimator.ofFloat(mCornerRadius, cornerRadius);
147             cornerAnimator.addUpdateListener((animation) -> {
148                 mCornerRadius = (float) animation.getAnimatedValue();
149             });
150 
151             // Animate height
152             ValueAnimator heightAnimator = ValueAnimator.ofInt(mContentHeight, contentHeight);
153             heightAnimator.addUpdateListener((animation) -> {
154                 mContentHeight = (int) animation.getAnimatedValue();
155                 mPanelView.invalidateOutline();
156             });
157 
158             // Animate width
159             ValueAnimator widthAnimator = ValueAnimator.ofInt(mContentWidth, contentWidth);
160             widthAnimator.addUpdateListener((animation) -> {
161                 mContentWidth = (int) animation.getAnimatedValue();
162             });
163 
164             // Play together
165             AnimatorSet as = new AnimatorSet();
166             as.setDuration(animateDurationMs);
167             as.setInterpolator(new AccelerateDecelerateInterpolator());
168             as.playTogether(cornerAnimator, heightAnimator, widthAnimator, marginAnimator);
169             as.start();
170 
171         } else {
172             mMargin = margin;
173             mCornerRadius = cornerRadius;
174             mContentWidth = contentWidth;
175             mContentHeight = contentHeight;
176             mPanelView.invalidateOutline();
177         }
178     }
179 
getContainerWidth()180     int getContainerWidth() {
181         return mContainerWidth;
182     }
183 
getContainerHeight()184     int getContainerHeight() {
185         return mContainerHeight;
186     }
187 
AuthPanelController(Context context, View panelView)188     AuthPanelController(Context context, View panelView) {
189         mContext = context;
190         mPanelView = panelView;
191         mCornerRadius = context.getResources()
192                 .getDimension(R.dimen.biometric_dialog_corner_size);
193         mMargin = (int) context.getResources()
194                 .getDimension(R.dimen.biometric_dialog_border_padding);
195         mPanelView.setOutlineProvider(this);
196         mPanelView.setClipToOutline(true);
197     }
198 
199 }
200