• 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 package com.android.keyguard;
17 
18 import android.animation.Animator;
19 import android.animation.AnimatorSet;
20 import android.animation.ArgbEvaluator;
21 import android.animation.ValueAnimator;
22 import android.annotation.Nullable;
23 import android.annotation.SuppressLint;
24 import android.content.Context;
25 import android.content.res.TypedArray;
26 import android.graphics.drawable.Drawable;
27 import android.graphics.drawable.GradientDrawable;
28 import android.view.ContextThemeWrapper;
29 import android.widget.TextView;
30 
31 import androidx.annotation.StyleRes;
32 
33 import com.android.systemui.Flags;
34 import com.android.systemui.bouncer.shared.constants.PinBouncerConstants.Animation;
35 import com.android.systemui.bouncer.shared.constants.PinBouncerConstants.Color;
36 
37 import java.util.ArrayList;
38 import java.util.List;
39 
40 /**
41  * Provides background color and radius animations for key pad buttons.
42  */
43 class NumPadAnimator {
44     private ValueAnimator mExpandAnimator;
45     private AnimatorSet mExpandAnimatorSet;
46     private ValueAnimator mContractAnimator;
47     private AnimatorSet mContractAnimatorSet;
48     private GradientDrawable mBackground;
49     private Drawable mImageButton;
50     private TextView mDigitTextView;
51     private int mNormalBackgroundColor;
52     private int mPressedBackgroundColor;
53     private int mTextColorPrimary;
54     private int mTextColorPressed;
55     private int mStyle;
56     private float mStartRadius;
57     private float mEndRadius;
58     private int mHeight;
59     private int mWidth;
60 
NumPadAnimator(Context context, final Drawable drawable, @StyleRes int style, Drawable buttonImage)61     NumPadAnimator(Context context, final Drawable drawable,
62             @StyleRes int style, Drawable buttonImage) {
63         this(context, drawable, style, null, buttonImage);
64     }
65 
NumPadAnimator(Context context, final Drawable drawable, @StyleRes int style, @Nullable TextView digitTextView, @Nullable Drawable buttonImage)66     NumPadAnimator(Context context, final Drawable drawable, @StyleRes int style,
67             @Nullable TextView digitTextView, @Nullable Drawable buttonImage) {
68         mStyle = style;
69         mBackground = (GradientDrawable) drawable;
70         mDigitTextView = digitTextView;
71         mImageButton = buttonImage;
72 
73         reloadColors(context);
74     }
75 
expand()76     public void expand() {
77         mExpandAnimatorSet.cancel();
78         mContractAnimatorSet.cancel();
79         mExpandAnimatorSet.start();
80     }
81 
contract()82     public void contract() {
83         mExpandAnimatorSet.cancel();
84         mContractAnimatorSet.cancel();
85         mContractAnimatorSet.start();
86     }
87 
setProgress(float progress)88     public void setProgress(float progress) {
89         mBackground.setCornerRadius(mEndRadius + (mStartRadius - mEndRadius) * progress);
90         int height = (int) (mHeight * 0.7f + mHeight * 0.3 * progress);
91         int difference = mHeight - height;
92 
93         int left = 0;
94         int top = difference / 2;
95         int right = mWidth;
96         int bottom = mHeight - difference / 2;
97         mBackground.setBounds(left, top, right, bottom);
98     }
99 
onLayout(int width, int height)100     void onLayout(int width, int height) {
101         boolean shouldUpdateHeight = height != mHeight;
102         mWidth = width;
103         mHeight = height;
104         mStartRadius = height / 2f;
105         mEndRadius = height / 4f;
106         mExpandAnimator.setFloatValues(mStartRadius, mEndRadius);
107         mContractAnimator.setFloatValues(mEndRadius, mStartRadius);
108         // Set initial corner radius.
109         if (shouldUpdateHeight) {
110             mBackground.setCornerRadius(mStartRadius);
111         }
112     }
113 
114     /**
115      * Reload colors from resources.
116      **/
reloadColors(Context context)117     void reloadColors(Context context) {
118         boolean isNumPadKey = mImageButton == null;
119 
120         if (!Flags.bouncerUiRevamp2()) {
121             int[] customAttrs = {android.R.attr.colorControlNormal};
122             ContextThemeWrapper ctw = new ContextThemeWrapper(context, mStyle);
123             @SuppressLint("ResourceType") TypedArray a = ctw.obtainStyledAttributes(customAttrs);
124 
125             mNormalBackgroundColor = a.getColor(0, context.getColor(Color.digitBg));
126 
127             a.recycle();
128         } else {
129             mNormalBackgroundColor = context.getColor(isNumPadKey ? Color.digitBg : Color.actionBg);
130         }
131 
132         mPressedBackgroundColor = context.getColor(Color.bgPressed);
133         mTextColorPressed = context.getColor(Color.digitPressed);
134 
135         mBackground.setColor(mNormalBackgroundColor);
136         mTextColorPrimary = context.getColor(isNumPadKey ? Color.digit : Color.action);
137         createAnimators();
138     }
139 
createAnimators()140     private void createAnimators() {
141         // Actual values will be updated later, usually during an onLayout() call
142         mExpandAnimator = ValueAnimator.ofFloat(0f, 1f);
143         mExpandAnimator.setDuration(Animation.expansionDuration);
144         mExpandAnimator.setInterpolator(Animation.expansionInterpolator);
145         mExpandAnimator.addUpdateListener(
146                 anim -> mBackground.setCornerRadius((float) anim.getAnimatedValue()));
147 
148         List<Animator> expandAnimators = new ArrayList<>();
149         ValueAnimator expandBackgroundColorAnimator = ValueAnimator.ofObject(new ArgbEvaluator(),
150                 mNormalBackgroundColor, mPressedBackgroundColor);
151         expandBackgroundColorAnimator.setDuration(Animation.expansionColorDuration);
152         expandBackgroundColorAnimator.setInterpolator(Animation.expansionInterpolator);
153         expandBackgroundColorAnimator.addUpdateListener(
154                 animator -> mBackground.setColor((int) animator.getAnimatedValue()));
155 
156         ValueAnimator expandTextColorAnimator =
157                 ValueAnimator.ofObject(new ArgbEvaluator(),
158                 mTextColorPrimary, mTextColorPressed);
159         expandTextColorAnimator.setInterpolator(Animation.expansionInterpolator);
160         expandTextColorAnimator.setDuration(Animation.expansionColorDuration);
161         expandTextColorAnimator.addUpdateListener(valueAnimator -> {
162             if (mDigitTextView != null) {
163                 mDigitTextView.setTextColor((int) valueAnimator.getAnimatedValue());
164             }
165             if (mImageButton != null) {
166                 mImageButton.setTint((int) valueAnimator.getAnimatedValue());
167             }
168         });
169 
170         expandAnimators.add(mExpandAnimator);
171         expandAnimators.add(expandBackgroundColorAnimator);
172         expandAnimators.add(expandTextColorAnimator);
173 
174         if (Flags.bouncerUiRevamp2()) {
175             ValueAnimator expandTextScaleAnimator = ValueAnimator.ofFloat(
176                     Animation.normalTextScaleX, Animation.pressedTextScaleX);
177             expandTextScaleAnimator.setInterpolator(Animation.expansionInterpolator);
178             expandTextScaleAnimator.setDuration(Animation.expansionDuration);
179             expandTextScaleAnimator.addUpdateListener(valueAnimator -> {
180                 if (mDigitTextView != null) {
181                     mDigitTextView.setTextScaleX((Float) valueAnimator.getAnimatedValue());
182                 }
183             });
184             expandAnimators.add(expandTextScaleAnimator);
185         }
186 
187         mExpandAnimatorSet = new AnimatorSet();
188         mExpandAnimatorSet.playTogether(expandAnimators);
189 
190         List<Animator> contractAnimators = new ArrayList<>();
191         mContractAnimator = ValueAnimator.ofFloat(1f, 0f);
192         mContractAnimator.setStartDelay(Animation.contractionStartDelay);
193         mContractAnimator.setDuration(Animation.contractionDuration);
194         mContractAnimator.setInterpolator(Animation.contractionRadiusInterpolator);
195         mContractAnimator.addUpdateListener(
196                 anim -> mBackground.setCornerRadius((float) anim.getAnimatedValue()));
197         ValueAnimator contractBackgroundColorAnimator = ValueAnimator.ofObject(new ArgbEvaluator(),
198                 mPressedBackgroundColor, mNormalBackgroundColor);
199         contractBackgroundColorAnimator.setInterpolator(Animation.contractionColorInterpolator);
200         contractBackgroundColorAnimator.setStartDelay(Animation.contractionStartDelay);
201         contractBackgroundColorAnimator.setDuration(Animation.contractionDuration);
202         contractBackgroundColorAnimator.addUpdateListener(
203                 animator -> mBackground.setColor((int) animator.getAnimatedValue()));
204 
205         ValueAnimator contractTextColorAnimator =
206                 ValueAnimator.ofObject(new ArgbEvaluator(), mTextColorPressed,
207                 mTextColorPrimary);
208         contractTextColorAnimator.setInterpolator(Animation.contractionColorInterpolator);
209         contractTextColorAnimator.setStartDelay(Animation.contractionStartDelay);
210         contractTextColorAnimator.setDuration(Animation.contractionDuration);
211         contractTextColorAnimator.addUpdateListener(valueAnimator -> {
212             if (mDigitTextView != null) {
213                 mDigitTextView.setTextColor((int) valueAnimator.getAnimatedValue());
214             }
215             if (mImageButton != null) {
216                 mImageButton.setTint((int) valueAnimator.getAnimatedValue());
217             }
218         });
219 
220         contractAnimators.add(mContractAnimator);
221         contractAnimators.add(contractBackgroundColorAnimator);
222         contractAnimators.add(contractTextColorAnimator);
223 
224         if (Flags.bouncerUiRevamp2()) {
225             ValueAnimator contractTextScaleAnimator = ValueAnimator.ofFloat(
226                     Animation.pressedTextScaleX, Animation.normalTextScaleX);
227             contractTextScaleAnimator.setInterpolator(Animation.contractionRadiusInterpolator);
228             contractTextScaleAnimator.setDuration(Animation.contractionDuration);
229             contractTextScaleAnimator.addUpdateListener(valueAnimator -> {
230                 if (mDigitTextView != null) {
231                     mDigitTextView.setTextScaleX((Float) valueAnimator.getAnimatedValue());
232                 }
233             });
234             contractAnimators.add(contractTextScaleAnimator);
235         }
236         mContractAnimatorSet = new AnimatorSet();
237         mContractAnimatorSet.playTogether(contractAnimators);
238     }
239 }
240 
241