12e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos/*
22e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos * Copyright (C) 2014 The Android Open Source Project
32e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos *
42e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos * Licensed under the Apache License, Version 2.0 (the "License");
52e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos * you may not use this file except in compliance with the License.
62e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos * You may obtain a copy of the License at
72e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos *
82e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos *      http://www.apache.org/licenses/LICENSE-2.0
92e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos *
102e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos * Unless required by applicable law or agreed to in writing, software
112e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos * distributed under the License is distributed on an "AS IS" BASIS,
122e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos * See the License for the specific language governing permissions and
142e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos * limitations under the License
152e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos */
162e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
172e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roospackage com.android.systemui.statusbar.phone;
182e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
192e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roosimport android.animation.Animator;
202e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roosimport android.animation.AnimatorListenerAdapter;
212e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roosimport android.animation.AnimatorSet;
222e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roosimport android.animation.ValueAnimator;
232e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roosimport android.content.Context;
242e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roosimport android.content.res.Resources;
252e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roosimport android.graphics.Canvas;
262e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roosimport android.graphics.Color;
272e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roosimport android.graphics.ColorFilter;
282e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roosimport android.graphics.Paint;
292e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roosimport android.graphics.PixelFormat;
302e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roosimport android.graphics.Rect;
312e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roosimport android.graphics.drawable.Drawable;
322e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roosimport android.view.animation.Interpolator;
332e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
3484c381b614feda2333df7858a550fb62148f3d41Lucas Dupinimport com.android.settingslib.Utils;
35c0d7058b14c24cd07912f5629c26b39b7b4673d5Winsonimport com.android.systemui.Interpolators;
36c18010f6720f606003cde3cd376ddacaca30f6e5Selim Cinekimport com.android.systemui.R;
37c18010f6720f606003cde3cd376ddacaca30f6e5Selim Cinek
382e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roospublic class TrustDrawable extends Drawable {
392e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
402e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private static final long ENTERING_FROM_UNSET_START_DELAY = 200;
412e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private static final long VISIBLE_DURATION = 1000;
422e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private static final long EXIT_DURATION = 500;
432e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private static final long ENTER_DURATION = 500;
442e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
452e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private static final int ALPHA_VISIBLE_MIN = 0x26;
462e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private static final int ALPHA_VISIBLE_MAX = 0x4c;
472e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
482e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private static final int STATE_UNSET = -1;
492e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private static final int STATE_GONE = 0;
502e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private static final int STATE_ENTERING = 1;
512e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private static final int STATE_VISIBLE = 2;
522e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private static final int STATE_EXITING = 3;
532e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
542e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private int mAlpha;
552e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private boolean mAnimating;
562e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
572e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private int mCurAlpha;
582e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private float mCurInnerRadius;
592e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private Animator mCurAnimator;
602e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private int mState = STATE_UNSET;
612e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private Paint mPaint;
622e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private boolean mTrustManaged;
632e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
642e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private final float mInnerRadiusVisibleMin;
652e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private final float mInnerRadiusVisibleMax;
662e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private final float mInnerRadiusExit;
672e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private final float mInnerRadiusEnter;
682e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private final float mThickness;
692e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
702e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private final Animator mVisibleAnimator;
712e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
722e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    public TrustDrawable(Context context) {
732e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        Resources r = context.getResources();
742e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        mInnerRadiusVisibleMin = r.getDimension(R.dimen.trust_circle_inner_radius_visible_min);
752e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        mInnerRadiusVisibleMax = r.getDimension(R.dimen.trust_circle_inner_radius_visible_max);
762e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        mInnerRadiusExit = r.getDimension(R.dimen.trust_circle_inner_radius_exit);
772e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        mInnerRadiusEnter = r.getDimension(R.dimen.trust_circle_inner_radius_enter);
782e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        mThickness = r.getDimension(R.dimen.trust_circle_thickness);
792e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
802e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        mCurInnerRadius = mInnerRadiusEnter;
812e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
822e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        mVisibleAnimator = makeVisibleAnimator();
832e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
842e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        mPaint = new Paint();
852e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        mPaint.setStyle(Paint.Style.STROKE);
86a360e1e70ff5bb40a950bfe6dd3250415ec99edaLucas Dupin        mPaint.setColor(Utils.getColorAttr(context, R.attr.wallpaperTextColor));
872e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        mPaint.setAntiAlias(true);
882e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        mPaint.setStrokeWidth(mThickness);
892e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    }
902e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
912e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    @Override
922e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    public void draw(Canvas canvas) {
932e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        int newAlpha = (mCurAlpha * mAlpha) / 256;
942e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        if (newAlpha == 0) {
952e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            return;
962e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        }
972e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        final Rect r = getBounds();
982e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        mPaint.setAlpha(newAlpha);
992e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        canvas.drawCircle(r.exactCenterX(), r.exactCenterY(), mCurInnerRadius, mPaint);
1002e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    }
1012e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
1022e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    @Override
1032e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    public void setAlpha(int alpha) {
1042e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        mAlpha = alpha;
1052e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    }
1062e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
1072e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    @Override
1082e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    public int getAlpha() {
1092e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        return mAlpha;
1102e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    }
1112e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
1122e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    @Override
113bd3bfc5285dcacff0a69fecf3baeeeb90d887a58Chris Craik    public void setColorFilter(ColorFilter colorFilter) {
1142e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        throw new UnsupportedOperationException("not implemented");
1152e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    }
1162e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
1172e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    @Override
1182e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    public int getOpacity() {
1192e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        return PixelFormat.TRANSLUCENT;
1202e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    }
1212e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
1222e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    public void start() {
1232e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        if (!mAnimating) {
1242e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            mAnimating = true;
1252e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            updateState(true);
1261540da4624ebdf674784a970892d4d4b7b64e775Adrian Roos            invalidateSelf();
1272e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        }
1282e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    }
1292e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
1302e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    public void stop() {
1312e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        if (mAnimating) {
1322e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            mAnimating = false;
1332e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            if (mCurAnimator != null) {
1342e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos                mCurAnimator.cancel();
1352e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos                mCurAnimator = null;
1362e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            }
1372e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            mState = STATE_UNSET;
1382e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            mCurAlpha = 0;
1392e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            mCurInnerRadius = mInnerRadiusEnter;
1401540da4624ebdf674784a970892d4d4b7b64e775Adrian Roos            invalidateSelf();
1412e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        }
1422e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    }
1432e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
1442e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    public void setTrustManaged(boolean trustManaged) {
1452e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        if (trustManaged == mTrustManaged && mState != STATE_UNSET) return;
1462e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        mTrustManaged = trustManaged;
1471540da4624ebdf674784a970892d4d4b7b64e775Adrian Roos        updateState(true);
1482e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    }
1492e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
1501540da4624ebdf674784a970892d4d4b7b64e775Adrian Roos    private void updateState(boolean allowTransientState) {
1511540da4624ebdf674784a970892d4d4b7b64e775Adrian Roos        if (!mAnimating) {
1521540da4624ebdf674784a970892d4d4b7b64e775Adrian Roos            return;
1531540da4624ebdf674784a970892d4d4b7b64e775Adrian Roos        }
1541540da4624ebdf674784a970892d4d4b7b64e775Adrian Roos
1552e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        int nextState = mState;
1562e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        if (mState == STATE_UNSET) {
1572e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            nextState = mTrustManaged ? STATE_ENTERING : STATE_GONE;
1582e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        } else if (mState == STATE_GONE) {
1592e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            if (mTrustManaged) nextState = STATE_ENTERING;
1602e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        } else if (mState == STATE_ENTERING) {
1612e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            if (!mTrustManaged) nextState = STATE_EXITING;
1622e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        } else if (mState == STATE_VISIBLE) {
1632e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            if (!mTrustManaged) nextState = STATE_EXITING;
1642e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        } else if (mState == STATE_EXITING) {
1652e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            if (mTrustManaged) nextState = STATE_ENTERING;
1662e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        }
1671540da4624ebdf674784a970892d4d4b7b64e775Adrian Roos        if (!allowTransientState) {
1682e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            if (nextState == STATE_ENTERING) nextState = STATE_VISIBLE;
1692e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            if (nextState == STATE_EXITING) nextState = STATE_GONE;
1702e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        }
1712e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
1722e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        if (nextState != mState) {
1732e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            if (mCurAnimator != null) {
1742e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos                mCurAnimator.cancel();
1752e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos                mCurAnimator = null;
1762e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            }
1772e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
1782e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            if (nextState == STATE_GONE) {
1792e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos                mCurAlpha = 0;
1802e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos                mCurInnerRadius = mInnerRadiusEnter;
1812e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            } else if (nextState == STATE_ENTERING) {
1822e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos                mCurAnimator = makeEnterAnimator(mCurInnerRadius, mCurAlpha);
1832e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos                if (mState == STATE_UNSET) {
1842e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos                    mCurAnimator.setStartDelay(ENTERING_FROM_UNSET_START_DELAY);
1852e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos                }
1862e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            } else if (nextState == STATE_VISIBLE) {
1872e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos                mCurAlpha = ALPHA_VISIBLE_MAX;
1882e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos                mCurInnerRadius = mInnerRadiusVisibleMax;
1892e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos                mCurAnimator = mVisibleAnimator;
1902e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            } else if (nextState == STATE_EXITING) {
1912e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos                mCurAnimator = makeExitAnimator(mCurInnerRadius, mCurAlpha);
1922e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            }
1932e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
1942e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            mState = nextState;
1952e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            if (mCurAnimator != null) {
1962e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos                mCurAnimator.start();
1972e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            }
1981540da4624ebdf674784a970892d4d4b7b64e775Adrian Roos            invalidateSelf();
1992e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        }
2002e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    }
2012e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
2022e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private Animator makeVisibleAnimator() {
2032e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        return makeAnimators(mInnerRadiusVisibleMax, mInnerRadiusVisibleMin,
2042e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos                ALPHA_VISIBLE_MAX, ALPHA_VISIBLE_MIN, VISIBLE_DURATION,
205c18010f6720f606003cde3cd376ddacaca30f6e5Selim Cinek                Interpolators.ACCELERATE_DECELERATE,
2062e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos                true /* repeating */, false /* stateUpdateListener */);
2072e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    }
2082e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
2092e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private Animator makeEnterAnimator(float radius, int alpha) {
2102e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        return makeAnimators(radius, mInnerRadiusVisibleMax,
211c18010f6720f606003cde3cd376ddacaca30f6e5Selim Cinek                alpha, ALPHA_VISIBLE_MAX, ENTER_DURATION, Interpolators.LINEAR_OUT_SLOW_IN,
2122e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos                false /* repeating */, true /* stateUpdateListener */);
2132e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    }
2142e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
2152e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private Animator makeExitAnimator(float radius, int alpha) {
2162e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        return makeAnimators(radius, mInnerRadiusExit,
217c18010f6720f606003cde3cd376ddacaca30f6e5Selim Cinek                alpha, 0, EXIT_DURATION, Interpolators.FAST_OUT_SLOW_IN,
2182e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos                false /* repeating */, true /* stateUpdateListener */);
2192e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    }
2202e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
2212e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private Animator makeAnimators(float startRadius, float endRadius,
2222e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            int startAlpha, int endAlpha, long duration, Interpolator interpolator,
2232e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            boolean repeating, boolean stateUpdateListener) {
2242e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        ValueAnimator alphaAnimator = configureAnimator(
2252e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos                ValueAnimator.ofInt(startAlpha, endAlpha),
2262e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos                duration, mAlphaUpdateListener, interpolator, repeating);
2272e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        ValueAnimator sizeAnimator = configureAnimator(
2282e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos                ValueAnimator.ofFloat(startRadius, endRadius),
2292e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos                duration, mRadiusUpdateListener, interpolator, repeating);
2302e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
2312e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        AnimatorSet set = new AnimatorSet();
2322e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        set.playTogether(alphaAnimator, sizeAnimator);
2332e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        if (stateUpdateListener) {
2342e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            set.addListener(new StateUpdateAnimatorListener());
2352e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        }
2362e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        return set;
2372e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    }
2382e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
2392e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private ValueAnimator configureAnimator(ValueAnimator animator, long duration,
2402e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            ValueAnimator.AnimatorUpdateListener updateListener, Interpolator interpolator,
2412e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            boolean repeating) {
2422e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        animator.setDuration(duration);
2432e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        animator.addUpdateListener(updateListener);
2442e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        animator.setInterpolator(interpolator);
2452e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        if (repeating) {
2462e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            animator.setRepeatCount(ValueAnimator.INFINITE);
2472e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            animator.setRepeatMode(ValueAnimator.REVERSE);
2482e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        }
2492e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        return animator;
2502e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    }
2512e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
2522e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private final ValueAnimator.AnimatorUpdateListener mAlphaUpdateListener =
2532e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            new ValueAnimator.AnimatorUpdateListener() {
2542e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        @Override
2552e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        public void onAnimationUpdate(ValueAnimator animation) {
2562e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            mCurAlpha = (int) animation.getAnimatedValue();
2572e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            invalidateSelf();
2582e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        }
2592e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    };
2602e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
2612e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private final ValueAnimator.AnimatorUpdateListener mRadiusUpdateListener =
2622e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            new ValueAnimator.AnimatorUpdateListener() {
2632e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        @Override
2642e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        public void onAnimationUpdate(ValueAnimator animation) {
2652e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            mCurInnerRadius = (float) animation.getAnimatedValue();
2662e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            invalidateSelf();
2672e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        }
2682e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    };
2692e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
2702e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    private class StateUpdateAnimatorListener extends AnimatorListenerAdapter {
2712e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        boolean mCancelled;
2722e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
2732e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        @Override
2742e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        public void onAnimationStart(Animator animation) {
2752e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            mCancelled = false;
2762e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        }
2772e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
2782e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        @Override
2792e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        public void onAnimationCancel(Animator animation) {
2802e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            mCancelled = true;
2812e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        }
2822e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos
2832e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        @Override
2842e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        public void onAnimationEnd(Animator animation) {
2852e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            if (!mCancelled) {
2862e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos                updateState(false);
2872e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos            }
2882e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos        }
2892e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos    }
2902e3ccbb37e21eb40308f83fb185209773147f78dAdrian Roos}
291