12fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi/*
22fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi * Copyright (C) 2014 The Android Open Source Project
32fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi *
42fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi * Licensed under the Apache License, Version 2.0 (the "License");
52fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi * you may not use this file except in compliance with the License.
62fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi * You may obtain a copy of the License at
72fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi *
82fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi *      http://www.apache.org/licenses/LICENSE-2.0
92fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi *
102fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi * Unless required by applicable law or agreed to in writing, software
112fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi * distributed under the License is distributed on an "AS IS" BASIS,
122fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi * See the License for the specific language governing permissions and
142fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi * limitations under the License
152fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi */
162fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
172fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggipackage com.android.systemui.assist;
182fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
192fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggiimport android.animation.Animator;
202fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggiimport android.animation.AnimatorListenerAdapter;
212fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggiimport android.animation.ValueAnimator;
222fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggiimport android.content.Context;
232fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggiimport android.graphics.Canvas;
242fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggiimport android.graphics.Outline;
252fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggiimport android.graphics.Paint;
262fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggiimport android.graphics.Rect;
272fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggiimport android.util.AttributeSet;
282fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggiimport android.view.View;
292fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggiimport android.view.ViewOutlineProvider;
302fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggiimport android.view.animation.Interpolator;
312fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggiimport android.view.animation.OvershootInterpolator;
322fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggiimport android.widget.FrameLayout;
332fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggiimport android.widget.ImageView;
342fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
35c0d7058b14c24cd07912f5629c26b39b7b4673d5Winsonimport com.android.systemui.Interpolators;
362fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggiimport com.android.systemui.R;
372fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
382fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggipublic class AssistOrbView extends FrameLayout {
392fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
402fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    private final int mCircleMinSize;
412fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    private final int mBaseMargin;
422fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    private final int mStaticOffset;
432fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    private final Paint mBackgroundPaint = new Paint();
442fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    private final Rect mCircleRect = new Rect();
452fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    private final Rect mStaticRect = new Rect();
462fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    private final Interpolator mOvershootInterpolator = new OvershootInterpolator();
472fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
482fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    private boolean mClipToOutline;
492fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    private final int mMaxElevation;
502fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    private float mOutlineAlpha;
512fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    private float mOffset;
522fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    private float mCircleSize;
532fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    private ImageView mLogo;
542fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    private float mCircleAnimationEndValue;
552fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
562fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    private ValueAnimator mOffsetAnimator;
572fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    private ValueAnimator mCircleAnimator;
582fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
592fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    private ValueAnimator.AnimatorUpdateListener mCircleUpdateListener
602fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi            = new ValueAnimator.AnimatorUpdateListener() {
612fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        @Override
622fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        public void onAnimationUpdate(ValueAnimator animation) {
632fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi            applyCircleSize((float) animation.getAnimatedValue());
642fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi            updateElevation();
652fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        }
662fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    };
672fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    private AnimatorListenerAdapter mClearAnimatorListener = new AnimatorListenerAdapter() {
682fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        @Override
692fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        public void onAnimationEnd(Animator animation) {
702fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi            mCircleAnimator = null;
712fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        }
722fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    };
732fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    private ValueAnimator.AnimatorUpdateListener mOffsetUpdateListener
742fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi            = new ValueAnimator.AnimatorUpdateListener() {
752fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        @Override
762fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        public void onAnimationUpdate(ValueAnimator animation) {
772fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi            mOffset = (float) animation.getAnimatedValue();
782fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi            updateLayout();
792fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        }
802fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    };
812fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
822fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
832fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    public AssistOrbView(Context context) {
842fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        this(context, null);
852fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    }
862fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
872fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    public AssistOrbView(Context context, AttributeSet attrs) {
882fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        this(context, attrs, 0);
892fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    }
902fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
912fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    public AssistOrbView(Context context, AttributeSet attrs, int defStyleAttr) {
922fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        this(context, attrs, defStyleAttr, 0);
932fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    }
942fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
952fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    public AssistOrbView(Context context, AttributeSet attrs, int defStyleAttr,
962fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi            int defStyleRes) {
972fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        super(context, attrs, defStyleAttr, defStyleRes);
982fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        setOutlineProvider(new ViewOutlineProvider() {
992fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi            @Override
1002fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi            public void getOutline(View view, Outline outline) {
1012fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi                if (mCircleSize > 0.0f) {
1022fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi                    outline.setOval(mCircleRect);
1032fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi                } else {
1042fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi                    outline.setEmpty();
1052fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi                }
1062fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi                outline.setAlpha(mOutlineAlpha);
1072fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi            }
1082fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        });
1092fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        setWillNotDraw(false);
1102fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        mCircleMinSize = context.getResources().getDimensionPixelSize(
1112fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi                R.dimen.assist_orb_size);
1122fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        mBaseMargin = context.getResources().getDimensionPixelSize(
1132fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi                R.dimen.assist_orb_base_margin);
1142fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        mStaticOffset = context.getResources().getDimensionPixelSize(
1152fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi                R.dimen.assist_orb_travel_distance);
1162fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        mMaxElevation = context.getResources().getDimensionPixelSize(
1172fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi                R.dimen.assist_orb_elevation);
1182fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        mBackgroundPaint.setAntiAlias(true);
1192fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        mBackgroundPaint.setColor(getResources().getColor(R.color.assist_orb_color));
1202fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    }
1212fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
1222fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    public ImageView getLogo() {
1232fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        return mLogo;
1242fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    }
1252fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
1262fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    @Override
1272fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    protected void onDraw(Canvas canvas) {
1282fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        super.onDraw(canvas);
1292fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        drawBackground(canvas);
1302fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    }
1312fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
1322fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    private void drawBackground(Canvas canvas) {
1332fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        canvas.drawCircle(mCircleRect.centerX(), mCircleRect.centerY(), mCircleSize / 2,
1342fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi                mBackgroundPaint);
1352fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    }
1362fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
1372fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    @Override
1382fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    protected void onFinishInflate() {
1392fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        super.onFinishInflate();
14051efddbd3bb304de2dd47fa8cd1114ac555958bbAlan Viverette        mLogo = findViewById(R.id.search_logo);
1412fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    }
1422fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
1432fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    @Override
1442fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    protected void onLayout(boolean changed, int l, int t, int r, int b) {
1452fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        mLogo.layout(0, 0, mLogo.getMeasuredWidth(), mLogo.getMeasuredHeight());
1462fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        if (changed) {
1472fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi            updateCircleRect(mStaticRect, mStaticOffset, true);
1482fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        }
1492fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    }
1502fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
1512fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    public void animateCircleSize(float circleSize, long duration,
1522fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi            long startDelay, Interpolator interpolator) {
1532fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        if (circleSize == mCircleAnimationEndValue) {
1542fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi            return;
1552fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        }
1562fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        if (mCircleAnimator != null) {
1572fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi            mCircleAnimator.cancel();
1582fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        }
1592fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        mCircleAnimator = ValueAnimator.ofFloat(mCircleSize, circleSize);
1602fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        mCircleAnimator.addUpdateListener(mCircleUpdateListener);
1612fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        mCircleAnimator.addListener(mClearAnimatorListener);
1622fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        mCircleAnimator.setInterpolator(interpolator);
1632fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        mCircleAnimator.setDuration(duration);
1642fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        mCircleAnimator.setStartDelay(startDelay);
1652fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        mCircleAnimator.start();
1662fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        mCircleAnimationEndValue = circleSize;
1672fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    }
1682fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
1692fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    private void applyCircleSize(float circleSize) {
1702fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        mCircleSize = circleSize;
1712fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        updateLayout();
1722fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    }
1732fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
1742fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    private void updateElevation() {
1752fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        float t = (mStaticOffset - mOffset) / (float) mStaticOffset;
1762fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        t = 1.0f - Math.max(t, 0.0f);
1772fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        float offset = t * mMaxElevation;
1782fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        setElevation(offset);
1792fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    }
1802fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
1812fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    /**
1822fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi     * Animates the offset to the edge of the screen.
1832fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi     *
1842fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi     * @param offset The offset to apply.
1852fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi     * @param startDelay The desired start delay if animated.
1862fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi     *
1872fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi     * @param interpolator The desired interpolator if animated. If null,
1882fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi     *                     a default interpolator will be taken designed for appearing or
1892fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi     *                     disappearing.
1902fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi     */
1912fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    private void animateOffset(float offset, long duration, long startDelay,
1922fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi            Interpolator interpolator) {
1932fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        if (mOffsetAnimator != null) {
1942fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi            mOffsetAnimator.removeAllListeners();
1952fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi            mOffsetAnimator.cancel();
1962fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        }
1972fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        mOffsetAnimator = ValueAnimator.ofFloat(mOffset, offset);
1982fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        mOffsetAnimator.addUpdateListener(mOffsetUpdateListener);
1992fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        mOffsetAnimator.addListener(new AnimatorListenerAdapter() {
2002fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi            @Override
2012fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi            public void onAnimationEnd(Animator animation) {
2022fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi                mOffsetAnimator = null;
2032fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi            }
2042fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        });
2052fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        mOffsetAnimator.setInterpolator(interpolator);
2062fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        mOffsetAnimator.setStartDelay(startDelay);
2072fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        mOffsetAnimator.setDuration(duration);
2082fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        mOffsetAnimator.start();
2092fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    }
2102fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
2112fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    private void updateLayout() {
2122fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        updateCircleRect();
2132fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        updateLogo();
2142fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        invalidateOutline();
2152fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        invalidate();
2162fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        updateClipping();
2172fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    }
2182fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
2192fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    private void updateClipping() {
2202fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        boolean clip = mCircleSize < mCircleMinSize;
2212fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        if (clip != mClipToOutline) {
2222fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi            setClipToOutline(clip);
2232fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi            mClipToOutline = clip;
2242fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        }
2252fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    }
2262fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
2272fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    private void updateLogo() {
2282fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        float translationX = (mCircleRect.left + mCircleRect.right) / 2.0f - mLogo.getWidth() / 2.0f;
2292fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        float translationY = (mCircleRect.top + mCircleRect.bottom) / 2.0f
2302fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi                - mLogo.getHeight() / 2.0f - mCircleMinSize / 7f;
2312fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        float t = (mStaticOffset - mOffset) / (float) mStaticOffset;
2322fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        translationY += t * mStaticOffset * 0.1f;
2332fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        float alpha = 1.0f-t;
2342fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        alpha = Math.max((alpha - 0.5f) * 2.0f, 0);
2352fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        mLogo.setImageAlpha((int) (alpha * 255));
2362fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        mLogo.setTranslationX(translationX);
2372fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        mLogo.setTranslationY(translationY);
2382fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    }
2392fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
2402fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    private void updateCircleRect() {
2412fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        updateCircleRect(mCircleRect, mOffset, false);
2422fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    }
2432fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
2442fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    private void updateCircleRect(Rect rect, float offset, boolean useStaticSize) {
2452fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        int left, top;
2462fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        float circleSize = useStaticSize ? mCircleMinSize : mCircleSize;
2472fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        left = (int) (getWidth() - circleSize) / 2;
2482fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        top = (int) (getHeight() - circleSize / 2 - mBaseMargin - offset);
2492fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        rect.set(left, top, (int) (left + circleSize), (int) (top + circleSize));
2502fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    }
2512fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
2522fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    public void startExitAnimation(long delay) {
253c18010f6720f606003cde3cd376ddacaca30f6e5Selim Cinek        animateCircleSize(0, 200, delay, Interpolators.FAST_OUT_LINEAR_IN);
254c18010f6720f606003cde3cd376ddacaca30f6e5Selim Cinek        animateOffset(0, 200, delay, Interpolators.FAST_OUT_LINEAR_IN);
2552fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    }
2562fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
2572fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    public void startEnterAnimation() {
2582fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        applyCircleSize(0);
2592fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        post(new Runnable() {
2602fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi            @Override
2612fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi            public void run() {
2622fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi                animateCircleSize(mCircleMinSize, 300, 0 /* delay */, mOvershootInterpolator);
263c18010f6720f606003cde3cd376ddacaca30f6e5Selim Cinek                animateOffset(mStaticOffset, 400, 0 /* delay */, Interpolators.LINEAR_OUT_SLOW_IN);
2642fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi            }
2652fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        });
2662fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    }
2672fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
2682fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    public void reset() {
2692fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        mClipToOutline = false;
2702fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        mBackgroundPaint.setAlpha(255);
2712fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        mOutlineAlpha = 1.0f;
2722fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    }
2732fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi
2742fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    @Override
2752fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    public boolean hasOverlappingRendering() {
2762fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        // not really true but it's ok during an animation, as it's never permanent
2772fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi        return false;
2782fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi    }
2792fdeeabe78b0f54f3163b1b3741ac813828b3511Jorim Jaggi}
280