Home | History | Annotate | Download | only in phone
      1 /*
      2  * Copyright (C) 2014 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.statusbar.phone;
     18 
     19 import android.animation.Animator;
     20 import android.animation.AnimatorListenerAdapter;
     21 import android.animation.AnimatorSet;
     22 import android.animation.ValueAnimator;
     23 import android.content.Context;
     24 import android.content.res.Resources;
     25 import android.graphics.Canvas;
     26 import android.graphics.Color;
     27 import android.graphics.ColorFilter;
     28 import android.graphics.Paint;
     29 import android.graphics.PixelFormat;
     30 import android.graphics.Rect;
     31 import android.graphics.drawable.Drawable;
     32 import android.view.animation.Interpolator;
     33 
     34 import com.android.settingslib.Utils;
     35 import com.android.systemui.Interpolators;
     36 import com.android.systemui.R;
     37 
     38 public class TrustDrawable extends Drawable {
     39 
     40     private static final long ENTERING_FROM_UNSET_START_DELAY = 200;
     41     private static final long VISIBLE_DURATION = 1000;
     42     private static final long EXIT_DURATION = 500;
     43     private static final long ENTER_DURATION = 500;
     44 
     45     private static final int ALPHA_VISIBLE_MIN = 0x26;
     46     private static final int ALPHA_VISIBLE_MAX = 0x4c;
     47 
     48     private static final int STATE_UNSET = -1;
     49     private static final int STATE_GONE = 0;
     50     private static final int STATE_ENTERING = 1;
     51     private static final int STATE_VISIBLE = 2;
     52     private static final int STATE_EXITING = 3;
     53 
     54     private int mAlpha;
     55     private boolean mAnimating;
     56 
     57     private int mCurAlpha;
     58     private float mCurInnerRadius;
     59     private Animator mCurAnimator;
     60     private int mState = STATE_UNSET;
     61     private Paint mPaint;
     62     private boolean mTrustManaged;
     63 
     64     private final float mInnerRadiusVisibleMin;
     65     private final float mInnerRadiusVisibleMax;
     66     private final float mInnerRadiusExit;
     67     private final float mInnerRadiusEnter;
     68     private final float mThickness;
     69 
     70     private final Animator mVisibleAnimator;
     71 
     72     public TrustDrawable(Context context) {
     73         Resources r = context.getResources();
     74         mInnerRadiusVisibleMin = r.getDimension(R.dimen.trust_circle_inner_radius_visible_min);
     75         mInnerRadiusVisibleMax = r.getDimension(R.dimen.trust_circle_inner_radius_visible_max);
     76         mInnerRadiusExit = r.getDimension(R.dimen.trust_circle_inner_radius_exit);
     77         mInnerRadiusEnter = r.getDimension(R.dimen.trust_circle_inner_radius_enter);
     78         mThickness = r.getDimension(R.dimen.trust_circle_thickness);
     79 
     80         mCurInnerRadius = mInnerRadiusEnter;
     81 
     82         mVisibleAnimator = makeVisibleAnimator();
     83 
     84         mPaint = new Paint();
     85         mPaint.setStyle(Paint.Style.STROKE);
     86         mPaint.setColor(Utils.getColorAttr(context, R.attr.wallpaperTextColor));
     87         mPaint.setAntiAlias(true);
     88         mPaint.setStrokeWidth(mThickness);
     89     }
     90 
     91     @Override
     92     public void draw(Canvas canvas) {
     93         int newAlpha = (mCurAlpha * mAlpha) / 256;
     94         if (newAlpha == 0) {
     95             return;
     96         }
     97         final Rect r = getBounds();
     98         mPaint.setAlpha(newAlpha);
     99         canvas.drawCircle(r.exactCenterX(), r.exactCenterY(), mCurInnerRadius, mPaint);
    100     }
    101 
    102     @Override
    103     public void setAlpha(int alpha) {
    104         mAlpha = alpha;
    105     }
    106 
    107     @Override
    108     public int getAlpha() {
    109         return mAlpha;
    110     }
    111 
    112     @Override
    113     public void setColorFilter(ColorFilter colorFilter) {
    114         throw new UnsupportedOperationException("not implemented");
    115     }
    116 
    117     @Override
    118     public int getOpacity() {
    119         return PixelFormat.TRANSLUCENT;
    120     }
    121 
    122     public void start() {
    123         if (!mAnimating) {
    124             mAnimating = true;
    125             updateState(true);
    126             invalidateSelf();
    127         }
    128     }
    129 
    130     public void stop() {
    131         if (mAnimating) {
    132             mAnimating = false;
    133             if (mCurAnimator != null) {
    134                 mCurAnimator.cancel();
    135                 mCurAnimator = null;
    136             }
    137             mState = STATE_UNSET;
    138             mCurAlpha = 0;
    139             mCurInnerRadius = mInnerRadiusEnter;
    140             invalidateSelf();
    141         }
    142     }
    143 
    144     public void setTrustManaged(boolean trustManaged) {
    145         if (trustManaged == mTrustManaged && mState != STATE_UNSET) return;
    146         mTrustManaged = trustManaged;
    147         updateState(true);
    148     }
    149 
    150     private void updateState(boolean allowTransientState) {
    151         if (!mAnimating) {
    152             return;
    153         }
    154 
    155         int nextState = mState;
    156         if (mState == STATE_UNSET) {
    157             nextState = mTrustManaged ? STATE_ENTERING : STATE_GONE;
    158         } else if (mState == STATE_GONE) {
    159             if (mTrustManaged) nextState = STATE_ENTERING;
    160         } else if (mState == STATE_ENTERING) {
    161             if (!mTrustManaged) nextState = STATE_EXITING;
    162         } else if (mState == STATE_VISIBLE) {
    163             if (!mTrustManaged) nextState = STATE_EXITING;
    164         } else if (mState == STATE_EXITING) {
    165             if (mTrustManaged) nextState = STATE_ENTERING;
    166         }
    167         if (!allowTransientState) {
    168             if (nextState == STATE_ENTERING) nextState = STATE_VISIBLE;
    169             if (nextState == STATE_EXITING) nextState = STATE_GONE;
    170         }
    171 
    172         if (nextState != mState) {
    173             if (mCurAnimator != null) {
    174                 mCurAnimator.cancel();
    175                 mCurAnimator = null;
    176             }
    177 
    178             if (nextState == STATE_GONE) {
    179                 mCurAlpha = 0;
    180                 mCurInnerRadius = mInnerRadiusEnter;
    181             } else if (nextState == STATE_ENTERING) {
    182                 mCurAnimator = makeEnterAnimator(mCurInnerRadius, mCurAlpha);
    183                 if (mState == STATE_UNSET) {
    184                     mCurAnimator.setStartDelay(ENTERING_FROM_UNSET_START_DELAY);
    185                 }
    186             } else if (nextState == STATE_VISIBLE) {
    187                 mCurAlpha = ALPHA_VISIBLE_MAX;
    188                 mCurInnerRadius = mInnerRadiusVisibleMax;
    189                 mCurAnimator = mVisibleAnimator;
    190             } else if (nextState == STATE_EXITING) {
    191                 mCurAnimator = makeExitAnimator(mCurInnerRadius, mCurAlpha);
    192             }
    193 
    194             mState = nextState;
    195             if (mCurAnimator != null) {
    196                 mCurAnimator.start();
    197             }
    198             invalidateSelf();
    199         }
    200     }
    201 
    202     private Animator makeVisibleAnimator() {
    203         return makeAnimators(mInnerRadiusVisibleMax, mInnerRadiusVisibleMin,
    204                 ALPHA_VISIBLE_MAX, ALPHA_VISIBLE_MIN, VISIBLE_DURATION,
    205                 Interpolators.ACCELERATE_DECELERATE,
    206                 true /* repeating */, false /* stateUpdateListener */);
    207     }
    208 
    209     private Animator makeEnterAnimator(float radius, int alpha) {
    210         return makeAnimators(radius, mInnerRadiusVisibleMax,
    211                 alpha, ALPHA_VISIBLE_MAX, ENTER_DURATION, Interpolators.LINEAR_OUT_SLOW_IN,
    212                 false /* repeating */, true /* stateUpdateListener */);
    213     }
    214 
    215     private Animator makeExitAnimator(float radius, int alpha) {
    216         return makeAnimators(radius, mInnerRadiusExit,
    217                 alpha, 0, EXIT_DURATION, Interpolators.FAST_OUT_SLOW_IN,
    218                 false /* repeating */, true /* stateUpdateListener */);
    219     }
    220 
    221     private Animator makeAnimators(float startRadius, float endRadius,
    222             int startAlpha, int endAlpha, long duration, Interpolator interpolator,
    223             boolean repeating, boolean stateUpdateListener) {
    224         ValueAnimator alphaAnimator = configureAnimator(
    225                 ValueAnimator.ofInt(startAlpha, endAlpha),
    226                 duration, mAlphaUpdateListener, interpolator, repeating);
    227         ValueAnimator sizeAnimator = configureAnimator(
    228                 ValueAnimator.ofFloat(startRadius, endRadius),
    229                 duration, mRadiusUpdateListener, interpolator, repeating);
    230 
    231         AnimatorSet set = new AnimatorSet();
    232         set.playTogether(alphaAnimator, sizeAnimator);
    233         if (stateUpdateListener) {
    234             set.addListener(new StateUpdateAnimatorListener());
    235         }
    236         return set;
    237     }
    238 
    239     private ValueAnimator configureAnimator(ValueAnimator animator, long duration,
    240             ValueAnimator.AnimatorUpdateListener updateListener, Interpolator interpolator,
    241             boolean repeating) {
    242         animator.setDuration(duration);
    243         animator.addUpdateListener(updateListener);
    244         animator.setInterpolator(interpolator);
    245         if (repeating) {
    246             animator.setRepeatCount(ValueAnimator.INFINITE);
    247             animator.setRepeatMode(ValueAnimator.REVERSE);
    248         }
    249         return animator;
    250     }
    251 
    252     private final ValueAnimator.AnimatorUpdateListener mAlphaUpdateListener =
    253             new ValueAnimator.AnimatorUpdateListener() {
    254         @Override
    255         public void onAnimationUpdate(ValueAnimator animation) {
    256             mCurAlpha = (int) animation.getAnimatedValue();
    257             invalidateSelf();
    258         }
    259     };
    260 
    261     private final ValueAnimator.AnimatorUpdateListener mRadiusUpdateListener =
    262             new ValueAnimator.AnimatorUpdateListener() {
    263         @Override
    264         public void onAnimationUpdate(ValueAnimator animation) {
    265             mCurInnerRadius = (float) animation.getAnimatedValue();
    266             invalidateSelf();
    267         }
    268     };
    269 
    270     private class StateUpdateAnimatorListener extends AnimatorListenerAdapter {
    271         boolean mCancelled;
    272 
    273         @Override
    274         public void onAnimationStart(Animator animation) {
    275             mCancelled = false;
    276         }
    277 
    278         @Override
    279         public void onAnimationCancel(Animator animation) {
    280             mCancelled = true;
    281         }
    282 
    283         @Override
    284         public void onAnimationEnd(Animator animation) {
    285             if (!mCancelled) {
    286                 updateState(false);
    287             }
    288         }
    289     }
    290 }
    291