1baa23274596246d03741457701ac515a73aa8818Selim Cinek/* 2baa23274596246d03741457701ac515a73aa8818Selim Cinek * Copyright (C) 2014 The Android Open Source Project 3baa23274596246d03741457701ac515a73aa8818Selim Cinek * 4baa23274596246d03741457701ac515a73aa8818Selim Cinek * Licensed under the Apache License, Version 2.0 (the "License"); 5baa23274596246d03741457701ac515a73aa8818Selim Cinek * you may not use this file except in compliance with the License. 6baa23274596246d03741457701ac515a73aa8818Selim Cinek * You may obtain a copy of the License at 7baa23274596246d03741457701ac515a73aa8818Selim Cinek * 8baa23274596246d03741457701ac515a73aa8818Selim Cinek * http://www.apache.org/licenses/LICENSE-2.0 9baa23274596246d03741457701ac515a73aa8818Selim Cinek * 10baa23274596246d03741457701ac515a73aa8818Selim Cinek * Unless required by applicable law or agreed to in writing, software 11baa23274596246d03741457701ac515a73aa8818Selim Cinek * distributed under the License is distributed on an "AS IS" BASIS, 12baa23274596246d03741457701ac515a73aa8818Selim Cinek * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13baa23274596246d03741457701ac515a73aa8818Selim Cinek * See the License for the specific language governing permissions and 14baa23274596246d03741457701ac515a73aa8818Selim Cinek * limitations under the License 15baa23274596246d03741457701ac515a73aa8818Selim Cinek */ 16baa23274596246d03741457701ac515a73aa8818Selim Cinek 17baa23274596246d03741457701ac515a73aa8818Selim Cinekpackage com.android.systemui.statusbar; 18baa23274596246d03741457701ac515a73aa8818Selim Cinek 19baa23274596246d03741457701ac515a73aa8818Selim Cinekimport android.animation.Animator; 20baa23274596246d03741457701ac515a73aa8818Selim Cinekimport android.animation.AnimatorListenerAdapter; 21baa23274596246d03741457701ac515a73aa8818Selim Cinekimport android.animation.ArgbEvaluator; 22baa23274596246d03741457701ac515a73aa8818Selim Cinekimport android.animation.PropertyValuesHolder; 23baa23274596246d03741457701ac515a73aa8818Selim Cinekimport android.animation.ValueAnimator; 24baa23274596246d03741457701ac515a73aa8818Selim Cinekimport android.content.Context; 25baa23274596246d03741457701ac515a73aa8818Selim Cinekimport android.graphics.Canvas; 26baa23274596246d03741457701ac515a73aa8818Selim Cinekimport android.graphics.Color; 27baa23274596246d03741457701ac515a73aa8818Selim Cinekimport android.graphics.Paint; 28baa23274596246d03741457701ac515a73aa8818Selim Cinekimport android.graphics.PorterDuff; 29baa23274596246d03741457701ac515a73aa8818Selim Cinekimport android.graphics.drawable.Drawable; 30baa23274596246d03741457701ac515a73aa8818Selim Cinekimport android.util.AttributeSet; 31b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggiimport android.view.View; 32b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggiimport android.view.ViewAnimationUtils; 33baa23274596246d03741457701ac515a73aa8818Selim Cinekimport android.view.animation.AnimationUtils; 34baa23274596246d03741457701ac515a73aa8818Selim Cinekimport android.view.animation.Interpolator; 35baa23274596246d03741457701ac515a73aa8818Selim Cinekimport android.widget.ImageView; 36baa23274596246d03741457701ac515a73aa8818Selim Cinekimport com.android.systemui.R; 37baa23274596246d03741457701ac515a73aa8818Selim Cinek 38baa23274596246d03741457701ac515a73aa8818Selim Cinek/** 39baa23274596246d03741457701ac515a73aa8818Selim Cinek * An ImageView which does not have overlapping renderings commands and therefore does not need a 40baa23274596246d03741457701ac515a73aa8818Selim Cinek * layer when alpha is changed. 41baa23274596246d03741457701ac515a73aa8818Selim Cinek */ 42baa23274596246d03741457701ac515a73aa8818Selim Cinekpublic class KeyguardAffordanceView extends ImageView { 43baa23274596246d03741457701ac515a73aa8818Selim Cinek 44baa23274596246d03741457701ac515a73aa8818Selim Cinek private static final long CIRCLE_APPEAR_DURATION = 80; 45baa23274596246d03741457701ac515a73aa8818Selim Cinek private static final long CIRCLE_DISAPPEAR_MAX_DURATION = 200; 46baa23274596246d03741457701ac515a73aa8818Selim Cinek private static final long NORMAL_ANIMATION_DURATION = 200; 47baa23274596246d03741457701ac515a73aa8818Selim Cinek public static final float MAX_ICON_SCALE_AMOUNT = 1.5f; 48baa23274596246d03741457701ac515a73aa8818Selim Cinek public static final float MIN_ICON_SCALE_AMOUNT = 0.8f; 49baa23274596246d03741457701ac515a73aa8818Selim Cinek 50baa23274596246d03741457701ac515a73aa8818Selim Cinek private final int mMinBackgroundRadius; 51baa23274596246d03741457701ac515a73aa8818Selim Cinek private final Paint mCirclePaint; 52baa23274596246d03741457701ac515a73aa8818Selim Cinek private final Interpolator mAppearInterpolator; 53baa23274596246d03741457701ac515a73aa8818Selim Cinek private final Interpolator mDisappearInterpolator; 54baa23274596246d03741457701ac515a73aa8818Selim Cinek private final int mInverseColor; 55baa23274596246d03741457701ac515a73aa8818Selim Cinek private final int mNormalColor; 56baa23274596246d03741457701ac515a73aa8818Selim Cinek private final ArgbEvaluator mColorInterpolator; 57baa23274596246d03741457701ac515a73aa8818Selim Cinek private final FlingAnimationUtils mFlingAnimationUtils; 58baa23274596246d03741457701ac515a73aa8818Selim Cinek private final Drawable mArrowDrawable; 59baa23274596246d03741457701ac515a73aa8818Selim Cinek private final int mHintChevronPadding; 60baa23274596246d03741457701ac515a73aa8818Selim Cinek private float mCircleRadius; 61baa23274596246d03741457701ac515a73aa8818Selim Cinek private int mCenterX; 62baa23274596246d03741457701ac515a73aa8818Selim Cinek private int mCenterY; 63baa23274596246d03741457701ac515a73aa8818Selim Cinek private ValueAnimator mCircleAnimator; 64baa23274596246d03741457701ac515a73aa8818Selim Cinek private ValueAnimator mAlphaAnimator; 65baa23274596246d03741457701ac515a73aa8818Selim Cinek private ValueAnimator mScaleAnimator; 66baa23274596246d03741457701ac515a73aa8818Selim Cinek private ValueAnimator mArrowAnimator; 67baa23274596246d03741457701ac515a73aa8818Selim Cinek private float mCircleStartValue; 68baa23274596246d03741457701ac515a73aa8818Selim Cinek private boolean mCircleWillBeHidden; 69baa23274596246d03741457701ac515a73aa8818Selim Cinek private int[] mTempPoint = new int[2]; 70baa23274596246d03741457701ac515a73aa8818Selim Cinek private float mImageScale; 71baa23274596246d03741457701ac515a73aa8818Selim Cinek private int mCircleColor; 72baa23274596246d03741457701ac515a73aa8818Selim Cinek private boolean mIsLeft; 73baa23274596246d03741457701ac515a73aa8818Selim Cinek private float mArrowAlpha = 0.0f; 74b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi private View mPreviewView; 75b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi private float mCircleStartRadius; 76b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi private float mMaxCircleSize; 77b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi private Animator mPreviewClipper; 78b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi private AnimatorListenerAdapter mClipEndListener = new AnimatorListenerAdapter() { 79b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi @Override 80b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi public void onAnimationEnd(Animator animation) { 81b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mPreviewClipper = null; 82b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi } 83b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi }; 84baa23274596246d03741457701ac515a73aa8818Selim Cinek private AnimatorListenerAdapter mCircleEndListener = new AnimatorListenerAdapter() { 85baa23274596246d03741457701ac515a73aa8818Selim Cinek @Override 86baa23274596246d03741457701ac515a73aa8818Selim Cinek public void onAnimationEnd(Animator animation) { 87baa23274596246d03741457701ac515a73aa8818Selim Cinek mCircleAnimator = null; 88baa23274596246d03741457701ac515a73aa8818Selim Cinek } 89baa23274596246d03741457701ac515a73aa8818Selim Cinek }; 90baa23274596246d03741457701ac515a73aa8818Selim Cinek private AnimatorListenerAdapter mScaleEndListener = new AnimatorListenerAdapter() { 91baa23274596246d03741457701ac515a73aa8818Selim Cinek @Override 92baa23274596246d03741457701ac515a73aa8818Selim Cinek public void onAnimationEnd(Animator animation) { 93baa23274596246d03741457701ac515a73aa8818Selim Cinek mScaleAnimator = null; 94baa23274596246d03741457701ac515a73aa8818Selim Cinek } 95baa23274596246d03741457701ac515a73aa8818Selim Cinek }; 96baa23274596246d03741457701ac515a73aa8818Selim Cinek private AnimatorListenerAdapter mAlphaEndListener = new AnimatorListenerAdapter() { 97baa23274596246d03741457701ac515a73aa8818Selim Cinek @Override 98baa23274596246d03741457701ac515a73aa8818Selim Cinek public void onAnimationEnd(Animator animation) { 99baa23274596246d03741457701ac515a73aa8818Selim Cinek mAlphaAnimator = null; 100baa23274596246d03741457701ac515a73aa8818Selim Cinek } 101baa23274596246d03741457701ac515a73aa8818Selim Cinek }; 102baa23274596246d03741457701ac515a73aa8818Selim Cinek private AnimatorListenerAdapter mArrowEndListener = new AnimatorListenerAdapter() { 103baa23274596246d03741457701ac515a73aa8818Selim Cinek @Override 104baa23274596246d03741457701ac515a73aa8818Selim Cinek public void onAnimationEnd(Animator animation) { 105baa23274596246d03741457701ac515a73aa8818Selim Cinek mArrowAnimator = null; 106baa23274596246d03741457701ac515a73aa8818Selim Cinek } 107baa23274596246d03741457701ac515a73aa8818Selim Cinek }; 108baa23274596246d03741457701ac515a73aa8818Selim Cinek 109baa23274596246d03741457701ac515a73aa8818Selim Cinek public KeyguardAffordanceView(Context context) { 110baa23274596246d03741457701ac515a73aa8818Selim Cinek this(context, null); 111baa23274596246d03741457701ac515a73aa8818Selim Cinek } 112baa23274596246d03741457701ac515a73aa8818Selim Cinek 113baa23274596246d03741457701ac515a73aa8818Selim Cinek public KeyguardAffordanceView(Context context, AttributeSet attrs) { 114baa23274596246d03741457701ac515a73aa8818Selim Cinek this(context, attrs, 0); 115baa23274596246d03741457701ac515a73aa8818Selim Cinek } 116baa23274596246d03741457701ac515a73aa8818Selim Cinek 117baa23274596246d03741457701ac515a73aa8818Selim Cinek public KeyguardAffordanceView(Context context, AttributeSet attrs, int defStyleAttr) { 118baa23274596246d03741457701ac515a73aa8818Selim Cinek this(context, attrs, defStyleAttr, 0); 119baa23274596246d03741457701ac515a73aa8818Selim Cinek } 120baa23274596246d03741457701ac515a73aa8818Selim Cinek 121baa23274596246d03741457701ac515a73aa8818Selim Cinek public KeyguardAffordanceView(Context context, AttributeSet attrs, int defStyleAttr, 122baa23274596246d03741457701ac515a73aa8818Selim Cinek int defStyleRes) { 123baa23274596246d03741457701ac515a73aa8818Selim Cinek super(context, attrs, defStyleAttr, defStyleRes); 124baa23274596246d03741457701ac515a73aa8818Selim Cinek mCirclePaint = new Paint(); 125baa23274596246d03741457701ac515a73aa8818Selim Cinek mCirclePaint.setAntiAlias(true); 126baa23274596246d03741457701ac515a73aa8818Selim Cinek mCircleColor = 0xffffffff; 127baa23274596246d03741457701ac515a73aa8818Selim Cinek mCirclePaint.setColor(mCircleColor); 128baa23274596246d03741457701ac515a73aa8818Selim Cinek 129baa23274596246d03741457701ac515a73aa8818Selim Cinek mNormalColor = 0xffffffff; 130baa23274596246d03741457701ac515a73aa8818Selim Cinek mInverseColor = 0xff000000; 131baa23274596246d03741457701ac515a73aa8818Selim Cinek mMinBackgroundRadius = mContext.getResources().getDimensionPixelSize( 132baa23274596246d03741457701ac515a73aa8818Selim Cinek R.dimen.keyguard_affordance_min_background_radius); 133baa23274596246d03741457701ac515a73aa8818Selim Cinek mHintChevronPadding = mContext.getResources().getDimensionPixelSize( 134baa23274596246d03741457701ac515a73aa8818Selim Cinek R.dimen.hint_chevron_circle_padding); 135baa23274596246d03741457701ac515a73aa8818Selim Cinek mAppearInterpolator = AnimationUtils.loadInterpolator(mContext, 136baa23274596246d03741457701ac515a73aa8818Selim Cinek android.R.interpolator.linear_out_slow_in); 137baa23274596246d03741457701ac515a73aa8818Selim Cinek mDisappearInterpolator = AnimationUtils.loadInterpolator(mContext, 138baa23274596246d03741457701ac515a73aa8818Selim Cinek android.R.interpolator.fast_out_linear_in); 139baa23274596246d03741457701ac515a73aa8818Selim Cinek mColorInterpolator = new ArgbEvaluator(); 140baa23274596246d03741457701ac515a73aa8818Selim Cinek mFlingAnimationUtils = new FlingAnimationUtils(mContext, 0.3f); 141baa23274596246d03741457701ac515a73aa8818Selim Cinek mArrowDrawable = context.getDrawable(R.drawable.ic_chevron_left); 142baa23274596246d03741457701ac515a73aa8818Selim Cinek mArrowDrawable.setBounds(0, 0, mArrowDrawable.getIntrinsicWidth(), 143baa23274596246d03741457701ac515a73aa8818Selim Cinek mArrowDrawable.getIntrinsicHeight()); 144baa23274596246d03741457701ac515a73aa8818Selim Cinek } 145baa23274596246d03741457701ac515a73aa8818Selim Cinek 146baa23274596246d03741457701ac515a73aa8818Selim Cinek @Override 147baa23274596246d03741457701ac515a73aa8818Selim Cinek protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 148baa23274596246d03741457701ac515a73aa8818Selim Cinek super.onLayout(changed, left, top, right, bottom); 149baa23274596246d03741457701ac515a73aa8818Selim Cinek mCenterX = getWidth() / 2; 150baa23274596246d03741457701ac515a73aa8818Selim Cinek mCenterY = getHeight() / 2; 151b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mMaxCircleSize = getMaxCircleSize(); 152baa23274596246d03741457701ac515a73aa8818Selim Cinek } 153baa23274596246d03741457701ac515a73aa8818Selim Cinek 154baa23274596246d03741457701ac515a73aa8818Selim Cinek @Override 155baa23274596246d03741457701ac515a73aa8818Selim Cinek protected void onDraw(Canvas canvas) { 156baa23274596246d03741457701ac515a73aa8818Selim Cinek drawBackgroundCircle(canvas); 157baa23274596246d03741457701ac515a73aa8818Selim Cinek drawArrow(canvas); 158baa23274596246d03741457701ac515a73aa8818Selim Cinek canvas.save(); 159baa23274596246d03741457701ac515a73aa8818Selim Cinek canvas.scale(mImageScale, mImageScale, getWidth() / 2, getHeight() / 2); 160baa23274596246d03741457701ac515a73aa8818Selim Cinek super.onDraw(canvas); 161baa23274596246d03741457701ac515a73aa8818Selim Cinek canvas.restore(); 162baa23274596246d03741457701ac515a73aa8818Selim Cinek } 163baa23274596246d03741457701ac515a73aa8818Selim Cinek 164b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi public void setPreviewView(View v) { 165b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mPreviewView = v; 1660d61b51852278de763d971ae0c57b27e6ed1ce6aSelim Cinek if (mPreviewView != null) { 1670d61b51852278de763d971ae0c57b27e6ed1ce6aSelim Cinek mPreviewView.setVisibility(INVISIBLE); 1680d61b51852278de763d971ae0c57b27e6ed1ce6aSelim Cinek } 169b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi } 170b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi 171baa23274596246d03741457701ac515a73aa8818Selim Cinek private void drawArrow(Canvas canvas) { 172baa23274596246d03741457701ac515a73aa8818Selim Cinek if (mArrowAlpha > 0) { 173baa23274596246d03741457701ac515a73aa8818Selim Cinek canvas.save(); 174baa23274596246d03741457701ac515a73aa8818Selim Cinek canvas.translate(mCenterX, mCenterY); 175baa23274596246d03741457701ac515a73aa8818Selim Cinek if (mIsLeft) { 176baa23274596246d03741457701ac515a73aa8818Selim Cinek canvas.scale(-1.0f, 1.0f); 177baa23274596246d03741457701ac515a73aa8818Selim Cinek } 178baa23274596246d03741457701ac515a73aa8818Selim Cinek canvas.translate(- mCircleRadius - mHintChevronPadding 179baa23274596246d03741457701ac515a73aa8818Selim Cinek - mArrowDrawable.getIntrinsicWidth() / 2, 180baa23274596246d03741457701ac515a73aa8818Selim Cinek - mArrowDrawable.getIntrinsicHeight() / 2); 181baa23274596246d03741457701ac515a73aa8818Selim Cinek mArrowDrawable.setAlpha((int) (mArrowAlpha * 255)); 182baa23274596246d03741457701ac515a73aa8818Selim Cinek mArrowDrawable.draw(canvas); 183baa23274596246d03741457701ac515a73aa8818Selim Cinek canvas.restore(); 184baa23274596246d03741457701ac515a73aa8818Selim Cinek } 185baa23274596246d03741457701ac515a73aa8818Selim Cinek } 186baa23274596246d03741457701ac515a73aa8818Selim Cinek 187baa23274596246d03741457701ac515a73aa8818Selim Cinek private void updateIconColor() { 188baa23274596246d03741457701ac515a73aa8818Selim Cinek Drawable drawable = getDrawable().mutate(); 189baa23274596246d03741457701ac515a73aa8818Selim Cinek float alpha = mCircleRadius / mMinBackgroundRadius; 190baa23274596246d03741457701ac515a73aa8818Selim Cinek alpha = Math.min(1.0f, alpha); 191baa23274596246d03741457701ac515a73aa8818Selim Cinek int color = (int) mColorInterpolator.evaluate(alpha, mNormalColor, mInverseColor); 192baa23274596246d03741457701ac515a73aa8818Selim Cinek drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP); 193baa23274596246d03741457701ac515a73aa8818Selim Cinek } 194baa23274596246d03741457701ac515a73aa8818Selim Cinek 195baa23274596246d03741457701ac515a73aa8818Selim Cinek private void drawBackgroundCircle(Canvas canvas) { 196baa23274596246d03741457701ac515a73aa8818Selim Cinek if (mCircleRadius > 0) { 197baa23274596246d03741457701ac515a73aa8818Selim Cinek updateCircleColor(); 198baa23274596246d03741457701ac515a73aa8818Selim Cinek canvas.drawCircle(mCenterX, mCenterY, mCircleRadius, mCirclePaint); 199baa23274596246d03741457701ac515a73aa8818Selim Cinek } 200baa23274596246d03741457701ac515a73aa8818Selim Cinek } 201baa23274596246d03741457701ac515a73aa8818Selim Cinek 202baa23274596246d03741457701ac515a73aa8818Selim Cinek private void updateCircleColor() { 203baa23274596246d03741457701ac515a73aa8818Selim Cinek float fraction = 0.5f + 0.5f * Math.max(0.0f, Math.min(1.0f, 204baa23274596246d03741457701ac515a73aa8818Selim Cinek (mCircleRadius - mMinBackgroundRadius) / (0.5f * mMinBackgroundRadius))); 205b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi if (mPreviewView != null) { 206b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi float finishingFraction = 1 - Math.max(0, mCircleRadius - mCircleStartRadius) 207b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi / (mMaxCircleSize - mCircleStartRadius); 208b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi fraction *= finishingFraction; 209b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi } 210baa23274596246d03741457701ac515a73aa8818Selim Cinek int color = Color.argb((int) (Color.alpha(mCircleColor) * fraction), 211baa23274596246d03741457701ac515a73aa8818Selim Cinek Color.red(mCircleColor), 212baa23274596246d03741457701ac515a73aa8818Selim Cinek Color.green(mCircleColor), Color.blue(mCircleColor)); 213baa23274596246d03741457701ac515a73aa8818Selim Cinek mCirclePaint.setColor(color); 214baa23274596246d03741457701ac515a73aa8818Selim Cinek } 215baa23274596246d03741457701ac515a73aa8818Selim Cinek 216baa23274596246d03741457701ac515a73aa8818Selim Cinek public void finishAnimation(float velocity, final Runnable mAnimationEndRunnable) { 217baa23274596246d03741457701ac515a73aa8818Selim Cinek cancelAnimator(mCircleAnimator); 218b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi cancelAnimator(mPreviewClipper); 219b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mCircleStartRadius = mCircleRadius; 220baa23274596246d03741457701ac515a73aa8818Selim Cinek float maxCircleSize = getMaxCircleSize(); 221baa23274596246d03741457701ac515a73aa8818Selim Cinek ValueAnimator animatorToRadius = getAnimatorToRadius(maxCircleSize); 222baa23274596246d03741457701ac515a73aa8818Selim Cinek mFlingAnimationUtils.applyDismissing(animatorToRadius, mCircleRadius, maxCircleSize, 223baa23274596246d03741457701ac515a73aa8818Selim Cinek velocity, maxCircleSize); 224baa23274596246d03741457701ac515a73aa8818Selim Cinek animatorToRadius.addListener(new AnimatorListenerAdapter() { 225baa23274596246d03741457701ac515a73aa8818Selim Cinek @Override 226baa23274596246d03741457701ac515a73aa8818Selim Cinek public void onAnimationEnd(Animator animation) { 227baa23274596246d03741457701ac515a73aa8818Selim Cinek mAnimationEndRunnable.run(); 228baa23274596246d03741457701ac515a73aa8818Selim Cinek } 229baa23274596246d03741457701ac515a73aa8818Selim Cinek }); 230baa23274596246d03741457701ac515a73aa8818Selim Cinek animatorToRadius.start(); 231baa23274596246d03741457701ac515a73aa8818Selim Cinek setImageAlpha(0, true); 232b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi if (mPreviewView != null) { 233b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mPreviewView.setVisibility(View.VISIBLE); 234b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mPreviewClipper = ViewAnimationUtils.createCircularReveal( 235b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mPreviewView, getLeft() + mCenterX, getTop() + mCenterY, mCircleRadius, 236b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi maxCircleSize); 237b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mFlingAnimationUtils.applyDismissing(mPreviewClipper, mCircleRadius, maxCircleSize, 238b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi velocity, maxCircleSize); 239b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mPreviewClipper.addListener(mClipEndListener); 240b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mPreviewClipper.start(); 241b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi } 242baa23274596246d03741457701ac515a73aa8818Selim Cinek } 243baa23274596246d03741457701ac515a73aa8818Selim Cinek 244baa23274596246d03741457701ac515a73aa8818Selim Cinek private float getMaxCircleSize() { 245baa23274596246d03741457701ac515a73aa8818Selim Cinek getLocationInWindow(mTempPoint); 246baa23274596246d03741457701ac515a73aa8818Selim Cinek float rootWidth = getRootView().getWidth(); 247baa23274596246d03741457701ac515a73aa8818Selim Cinek float width = mTempPoint[0] + mCenterX; 248baa23274596246d03741457701ac515a73aa8818Selim Cinek width = Math.max(rootWidth - width, width); 249baa23274596246d03741457701ac515a73aa8818Selim Cinek float height = mTempPoint[1] + mCenterY; 250baa23274596246d03741457701ac515a73aa8818Selim Cinek return (float) Math.hypot(width, height); 251baa23274596246d03741457701ac515a73aa8818Selim Cinek } 252baa23274596246d03741457701ac515a73aa8818Selim Cinek 253baa23274596246d03741457701ac515a73aa8818Selim Cinek public void setCircleRadius(float circleRadius) { 2545386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek setCircleRadius(circleRadius, false, false); 2555386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek } 2565386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek 2575386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek public void setCircleRadius(float circleRadius, boolean slowAnimation) { 2585386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek setCircleRadius(circleRadius, slowAnimation, false); 259baa23274596246d03741457701ac515a73aa8818Selim Cinek } 260baa23274596246d03741457701ac515a73aa8818Selim Cinek 261baa23274596246d03741457701ac515a73aa8818Selim Cinek public void setCircleRadiusWithoutAnimation(float circleRadius) { 262baa23274596246d03741457701ac515a73aa8818Selim Cinek cancelAnimator(mCircleAnimator); 2635386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek setCircleRadius(circleRadius, false ,true); 264baa23274596246d03741457701ac515a73aa8818Selim Cinek } 265baa23274596246d03741457701ac515a73aa8818Selim Cinek 2665386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek private void setCircleRadius(float circleRadius, boolean slowAnimation, boolean noAnimation) { 267baa23274596246d03741457701ac515a73aa8818Selim Cinek 268baa23274596246d03741457701ac515a73aa8818Selim Cinek // Check if we need a new animation 269baa23274596246d03741457701ac515a73aa8818Selim Cinek boolean radiusHidden = (mCircleAnimator != null && mCircleWillBeHidden) 270baa23274596246d03741457701ac515a73aa8818Selim Cinek || (mCircleAnimator == null && mCircleRadius == 0.0f); 271baa23274596246d03741457701ac515a73aa8818Selim Cinek boolean nowHidden = circleRadius == 0.0f; 272baa23274596246d03741457701ac515a73aa8818Selim Cinek boolean radiusNeedsAnimation = (radiusHidden != nowHidden) && !noAnimation; 273baa23274596246d03741457701ac515a73aa8818Selim Cinek if (!radiusNeedsAnimation) { 274baa23274596246d03741457701ac515a73aa8818Selim Cinek if (mCircleAnimator == null) { 275baa23274596246d03741457701ac515a73aa8818Selim Cinek mCircleRadius = circleRadius; 2760b75f83f142a4de5be77238c6030228e1b943aa2Jorim Jaggi updateIconColor(); 277baa23274596246d03741457701ac515a73aa8818Selim Cinek invalidate(); 278b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi if (nowHidden) { 279b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi if (mPreviewView != null) { 280b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mPreviewView.setVisibility(View.INVISIBLE); 281b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi } 282b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi } 283baa23274596246d03741457701ac515a73aa8818Selim Cinek } else if (!mCircleWillBeHidden) { 284baa23274596246d03741457701ac515a73aa8818Selim Cinek 285baa23274596246d03741457701ac515a73aa8818Selim Cinek // We just update the end value 286baa23274596246d03741457701ac515a73aa8818Selim Cinek float diff = circleRadius - mMinBackgroundRadius; 287baa23274596246d03741457701ac515a73aa8818Selim Cinek PropertyValuesHolder[] values = mCircleAnimator.getValues(); 288baa23274596246d03741457701ac515a73aa8818Selim Cinek values[0].setFloatValues(mCircleStartValue + diff, circleRadius); 289baa23274596246d03741457701ac515a73aa8818Selim Cinek mCircleAnimator.setCurrentPlayTime(mCircleAnimator.getCurrentPlayTime()); 290baa23274596246d03741457701ac515a73aa8818Selim Cinek } 291baa23274596246d03741457701ac515a73aa8818Selim Cinek } else { 292baa23274596246d03741457701ac515a73aa8818Selim Cinek cancelAnimator(mCircleAnimator); 293b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi cancelAnimator(mPreviewClipper); 294baa23274596246d03741457701ac515a73aa8818Selim Cinek ValueAnimator animator = getAnimatorToRadius(circleRadius); 295baa23274596246d03741457701ac515a73aa8818Selim Cinek Interpolator interpolator = circleRadius == 0.0f 296baa23274596246d03741457701ac515a73aa8818Selim Cinek ? mDisappearInterpolator 297baa23274596246d03741457701ac515a73aa8818Selim Cinek : mAppearInterpolator; 298baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.setInterpolator(interpolator); 2995386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek long duration = 250; 3005386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek if (!slowAnimation) { 3015386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek float durationFactor = Math.abs(mCircleRadius - circleRadius) 3025386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek / (float) mMinBackgroundRadius; 3035386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek duration = (long) (CIRCLE_APPEAR_DURATION * durationFactor); 3045386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek duration = Math.min(duration, CIRCLE_DISAPPEAR_MAX_DURATION); 3055386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek } 306baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.setDuration(duration); 307baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.start(); 3080d61b51852278de763d971ae0c57b27e6ed1ce6aSelim Cinek if (mPreviewView != null && mPreviewView.getVisibility() == View.VISIBLE) { 309b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mPreviewView.setVisibility(View.VISIBLE); 310b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mPreviewClipper = ViewAnimationUtils.createCircularReveal( 311b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mPreviewView, getLeft() + mCenterX, getTop() + mCenterY, mCircleRadius, 312b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi circleRadius); 313b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mPreviewClipper.setInterpolator(interpolator); 314b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mPreviewClipper.setDuration(duration); 315b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mPreviewClipper.addListener(mClipEndListener); 316b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mPreviewClipper.addListener(new AnimatorListenerAdapter() { 317b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi @Override 318b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi public void onAnimationEnd(Animator animation) { 319b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mPreviewView.setVisibility(View.INVISIBLE); 320b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi } 321b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi }); 322b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mPreviewClipper.start(); 323b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi } 324baa23274596246d03741457701ac515a73aa8818Selim Cinek } 325baa23274596246d03741457701ac515a73aa8818Selim Cinek } 326baa23274596246d03741457701ac515a73aa8818Selim Cinek 327baa23274596246d03741457701ac515a73aa8818Selim Cinek private ValueAnimator getAnimatorToRadius(float circleRadius) { 328baa23274596246d03741457701ac515a73aa8818Selim Cinek ValueAnimator animator = ValueAnimator.ofFloat(mCircleRadius, circleRadius); 329baa23274596246d03741457701ac515a73aa8818Selim Cinek mCircleAnimator = animator; 330baa23274596246d03741457701ac515a73aa8818Selim Cinek mCircleStartValue = mCircleRadius; 331baa23274596246d03741457701ac515a73aa8818Selim Cinek mCircleWillBeHidden = circleRadius == 0.0f; 332baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 333baa23274596246d03741457701ac515a73aa8818Selim Cinek @Override 334baa23274596246d03741457701ac515a73aa8818Selim Cinek public void onAnimationUpdate(ValueAnimator animation) { 335baa23274596246d03741457701ac515a73aa8818Selim Cinek mCircleRadius = (float) animation.getAnimatedValue(); 3360b75f83f142a4de5be77238c6030228e1b943aa2Jorim Jaggi updateIconColor(); 337baa23274596246d03741457701ac515a73aa8818Selim Cinek invalidate(); 338baa23274596246d03741457701ac515a73aa8818Selim Cinek } 339baa23274596246d03741457701ac515a73aa8818Selim Cinek }); 340baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.addListener(mCircleEndListener); 341baa23274596246d03741457701ac515a73aa8818Selim Cinek return animator; 342baa23274596246d03741457701ac515a73aa8818Selim Cinek } 343baa23274596246d03741457701ac515a73aa8818Selim Cinek 344baa23274596246d03741457701ac515a73aa8818Selim Cinek private void cancelAnimator(Animator animator) { 345baa23274596246d03741457701ac515a73aa8818Selim Cinek if (animator != null) { 346baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.cancel(); 347baa23274596246d03741457701ac515a73aa8818Selim Cinek } 348baa23274596246d03741457701ac515a73aa8818Selim Cinek } 349baa23274596246d03741457701ac515a73aa8818Selim Cinek 350baa23274596246d03741457701ac515a73aa8818Selim Cinek public void setImageScale(float imageScale, boolean animate) { 351baa23274596246d03741457701ac515a73aa8818Selim Cinek setImageScale(imageScale, animate, -1, null); 352baa23274596246d03741457701ac515a73aa8818Selim Cinek } 353baa23274596246d03741457701ac515a73aa8818Selim Cinek 354baa23274596246d03741457701ac515a73aa8818Selim Cinek /** 355baa23274596246d03741457701ac515a73aa8818Selim Cinek * Sets the scale of the containing image 356baa23274596246d03741457701ac515a73aa8818Selim Cinek * 357baa23274596246d03741457701ac515a73aa8818Selim Cinek * @param imageScale The new Scale. 358baa23274596246d03741457701ac515a73aa8818Selim Cinek * @param animate Should an animation be performed 359baa23274596246d03741457701ac515a73aa8818Selim Cinek * @param duration If animate, whats the duration? When -1 we take the default duration 360baa23274596246d03741457701ac515a73aa8818Selim Cinek * @param interpolator If animate, whats the interpolator? When null we take the default 361baa23274596246d03741457701ac515a73aa8818Selim Cinek * interpolator. 362baa23274596246d03741457701ac515a73aa8818Selim Cinek */ 363baa23274596246d03741457701ac515a73aa8818Selim Cinek public void setImageScale(float imageScale, boolean animate, long duration, 364baa23274596246d03741457701ac515a73aa8818Selim Cinek Interpolator interpolator) { 365baa23274596246d03741457701ac515a73aa8818Selim Cinek cancelAnimator(mScaleAnimator); 366baa23274596246d03741457701ac515a73aa8818Selim Cinek if (!animate) { 367baa23274596246d03741457701ac515a73aa8818Selim Cinek mImageScale = imageScale; 368baa23274596246d03741457701ac515a73aa8818Selim Cinek invalidate(); 369baa23274596246d03741457701ac515a73aa8818Selim Cinek } else { 370baa23274596246d03741457701ac515a73aa8818Selim Cinek ValueAnimator animator = ValueAnimator.ofFloat(mImageScale, imageScale); 371baa23274596246d03741457701ac515a73aa8818Selim Cinek mScaleAnimator = animator; 372baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 373baa23274596246d03741457701ac515a73aa8818Selim Cinek @Override 374baa23274596246d03741457701ac515a73aa8818Selim Cinek public void onAnimationUpdate(ValueAnimator animation) { 375baa23274596246d03741457701ac515a73aa8818Selim Cinek mImageScale = (float) animation.getAnimatedValue(); 376baa23274596246d03741457701ac515a73aa8818Selim Cinek invalidate(); 377baa23274596246d03741457701ac515a73aa8818Selim Cinek } 378baa23274596246d03741457701ac515a73aa8818Selim Cinek }); 379baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.addListener(mScaleEndListener); 380baa23274596246d03741457701ac515a73aa8818Selim Cinek if (interpolator == null) { 381baa23274596246d03741457701ac515a73aa8818Selim Cinek interpolator = imageScale == 0.0f 382baa23274596246d03741457701ac515a73aa8818Selim Cinek ? mDisappearInterpolator 383baa23274596246d03741457701ac515a73aa8818Selim Cinek : mAppearInterpolator; 384baa23274596246d03741457701ac515a73aa8818Selim Cinek } 385baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.setInterpolator(interpolator); 386baa23274596246d03741457701ac515a73aa8818Selim Cinek if (duration == -1) { 387baa23274596246d03741457701ac515a73aa8818Selim Cinek float durationFactor = Math.abs(mImageScale - imageScale) 388baa23274596246d03741457701ac515a73aa8818Selim Cinek / (1.0f - MIN_ICON_SCALE_AMOUNT); 389baa23274596246d03741457701ac515a73aa8818Selim Cinek durationFactor = Math.min(1.0f, durationFactor); 390baa23274596246d03741457701ac515a73aa8818Selim Cinek duration = (long) (NORMAL_ANIMATION_DURATION * durationFactor); 391baa23274596246d03741457701ac515a73aa8818Selim Cinek } 392baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.setDuration(duration); 393baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.start(); 394baa23274596246d03741457701ac515a73aa8818Selim Cinek } 395baa23274596246d03741457701ac515a73aa8818Selim Cinek } 396baa23274596246d03741457701ac515a73aa8818Selim Cinek 397baa23274596246d03741457701ac515a73aa8818Selim Cinek public void setImageAlpha(float alpha, boolean animate) { 398baa23274596246d03741457701ac515a73aa8818Selim Cinek setImageAlpha(alpha, animate, -1, null, null); 399baa23274596246d03741457701ac515a73aa8818Selim Cinek } 400baa23274596246d03741457701ac515a73aa8818Selim Cinek 401baa23274596246d03741457701ac515a73aa8818Selim Cinek /** 402baa23274596246d03741457701ac515a73aa8818Selim Cinek * Sets the alpha of the containing image 403baa23274596246d03741457701ac515a73aa8818Selim Cinek * 404baa23274596246d03741457701ac515a73aa8818Selim Cinek * @param alpha The new alpha. 405baa23274596246d03741457701ac515a73aa8818Selim Cinek * @param animate Should an animation be performed 406baa23274596246d03741457701ac515a73aa8818Selim Cinek * @param duration If animate, whats the duration? When -1 we take the default duration 407baa23274596246d03741457701ac515a73aa8818Selim Cinek * @param interpolator If animate, whats the interpolator? When null we take the default 408baa23274596246d03741457701ac515a73aa8818Selim Cinek * interpolator. 409baa23274596246d03741457701ac515a73aa8818Selim Cinek */ 410baa23274596246d03741457701ac515a73aa8818Selim Cinek public void setImageAlpha(float alpha, boolean animate, long duration, 411baa23274596246d03741457701ac515a73aa8818Selim Cinek Interpolator interpolator, Runnable runnable) { 412baa23274596246d03741457701ac515a73aa8818Selim Cinek cancelAnimator(mAlphaAnimator); 413baa23274596246d03741457701ac515a73aa8818Selim Cinek int endAlpha = (int) (alpha * 255); 4144ebcdfdd4294cc52a68fb150bc7a34f005290ea3Adrian Roos final Drawable background = getBackground(); 415baa23274596246d03741457701ac515a73aa8818Selim Cinek if (!animate) { 4164ebcdfdd4294cc52a68fb150bc7a34f005290ea3Adrian Roos if (background != null) background.mutate().setAlpha(endAlpha); 417baa23274596246d03741457701ac515a73aa8818Selim Cinek setImageAlpha(endAlpha); 418baa23274596246d03741457701ac515a73aa8818Selim Cinek } else { 419baa23274596246d03741457701ac515a73aa8818Selim Cinek int currentAlpha = getImageAlpha(); 420baa23274596246d03741457701ac515a73aa8818Selim Cinek ValueAnimator animator = ValueAnimator.ofInt(currentAlpha, endAlpha); 421baa23274596246d03741457701ac515a73aa8818Selim Cinek mAlphaAnimator = animator; 422baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 423baa23274596246d03741457701ac515a73aa8818Selim Cinek @Override 424baa23274596246d03741457701ac515a73aa8818Selim Cinek public void onAnimationUpdate(ValueAnimator animation) { 4254ebcdfdd4294cc52a68fb150bc7a34f005290ea3Adrian Roos int alpha = (int) animation.getAnimatedValue(); 4264ebcdfdd4294cc52a68fb150bc7a34f005290ea3Adrian Roos if (background != null) background.mutate().setAlpha(alpha); 4274ebcdfdd4294cc52a68fb150bc7a34f005290ea3Adrian Roos setImageAlpha(alpha); 428baa23274596246d03741457701ac515a73aa8818Selim Cinek } 429baa23274596246d03741457701ac515a73aa8818Selim Cinek }); 430baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.addListener(mAlphaEndListener); 431baa23274596246d03741457701ac515a73aa8818Selim Cinek if (interpolator == null) { 432baa23274596246d03741457701ac515a73aa8818Selim Cinek interpolator = alpha == 0.0f 433baa23274596246d03741457701ac515a73aa8818Selim Cinek ? mDisappearInterpolator 434baa23274596246d03741457701ac515a73aa8818Selim Cinek : mAppearInterpolator; 435baa23274596246d03741457701ac515a73aa8818Selim Cinek } 436baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.setInterpolator(interpolator); 437baa23274596246d03741457701ac515a73aa8818Selim Cinek if (duration == -1) { 438baa23274596246d03741457701ac515a73aa8818Selim Cinek float durationFactor = Math.abs(currentAlpha - endAlpha) / 255f; 439baa23274596246d03741457701ac515a73aa8818Selim Cinek durationFactor = Math.min(1.0f, durationFactor); 440baa23274596246d03741457701ac515a73aa8818Selim Cinek duration = (long) (NORMAL_ANIMATION_DURATION * durationFactor); 441baa23274596246d03741457701ac515a73aa8818Selim Cinek } 442baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.setDuration(duration); 443baa23274596246d03741457701ac515a73aa8818Selim Cinek if (runnable != null) { 444baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.addListener(getEndListener(runnable)); 445baa23274596246d03741457701ac515a73aa8818Selim Cinek } 446baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.start(); 447baa23274596246d03741457701ac515a73aa8818Selim Cinek } 448baa23274596246d03741457701ac515a73aa8818Selim Cinek } 449baa23274596246d03741457701ac515a73aa8818Selim Cinek 450baa23274596246d03741457701ac515a73aa8818Selim Cinek private Animator.AnimatorListener getEndListener(final Runnable runnable) { 451baa23274596246d03741457701ac515a73aa8818Selim Cinek return new AnimatorListenerAdapter() { 452baa23274596246d03741457701ac515a73aa8818Selim Cinek boolean mCancelled; 453baa23274596246d03741457701ac515a73aa8818Selim Cinek @Override 454baa23274596246d03741457701ac515a73aa8818Selim Cinek public void onAnimationCancel(Animator animation) { 455baa23274596246d03741457701ac515a73aa8818Selim Cinek mCancelled = true; 456baa23274596246d03741457701ac515a73aa8818Selim Cinek } 457baa23274596246d03741457701ac515a73aa8818Selim Cinek 458baa23274596246d03741457701ac515a73aa8818Selim Cinek @Override 459baa23274596246d03741457701ac515a73aa8818Selim Cinek public void onAnimationEnd(Animator animation) { 460baa23274596246d03741457701ac515a73aa8818Selim Cinek if (!mCancelled) { 461baa23274596246d03741457701ac515a73aa8818Selim Cinek runnable.run(); 462baa23274596246d03741457701ac515a73aa8818Selim Cinek } 463baa23274596246d03741457701ac515a73aa8818Selim Cinek } 464baa23274596246d03741457701ac515a73aa8818Selim Cinek }; 465baa23274596246d03741457701ac515a73aa8818Selim Cinek } 466baa23274596246d03741457701ac515a73aa8818Selim Cinek 467baa23274596246d03741457701ac515a73aa8818Selim Cinek public float getCircleRadius() { 468baa23274596246d03741457701ac515a73aa8818Selim Cinek return mCircleRadius; 469baa23274596246d03741457701ac515a73aa8818Selim Cinek } 470baa23274596246d03741457701ac515a73aa8818Selim Cinek 471baa23274596246d03741457701ac515a73aa8818Selim Cinek public void showArrow(boolean show) { 472baa23274596246d03741457701ac515a73aa8818Selim Cinek cancelAnimator(mArrowAnimator); 473baa23274596246d03741457701ac515a73aa8818Selim Cinek float targetAlpha = show ? 1.0f : 0.0f; 474baa23274596246d03741457701ac515a73aa8818Selim Cinek if (mArrowAlpha == targetAlpha) { 475baa23274596246d03741457701ac515a73aa8818Selim Cinek return; 476baa23274596246d03741457701ac515a73aa8818Selim Cinek } 477baa23274596246d03741457701ac515a73aa8818Selim Cinek ValueAnimator animator = ValueAnimator.ofFloat(mArrowAlpha, targetAlpha); 478baa23274596246d03741457701ac515a73aa8818Selim Cinek mArrowAnimator = animator; 479baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 480baa23274596246d03741457701ac515a73aa8818Selim Cinek @Override 481baa23274596246d03741457701ac515a73aa8818Selim Cinek public void onAnimationUpdate(ValueAnimator animation) { 482baa23274596246d03741457701ac515a73aa8818Selim Cinek mArrowAlpha = (float) animation.getAnimatedValue(); 483baa23274596246d03741457701ac515a73aa8818Selim Cinek invalidate(); 484baa23274596246d03741457701ac515a73aa8818Selim Cinek } 485baa23274596246d03741457701ac515a73aa8818Selim Cinek }); 486baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.addListener(mArrowEndListener); 487baa23274596246d03741457701ac515a73aa8818Selim Cinek Interpolator interpolator = show 488baa23274596246d03741457701ac515a73aa8818Selim Cinek ? mAppearInterpolator 489baa23274596246d03741457701ac515a73aa8818Selim Cinek : mDisappearInterpolator; 490baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.setInterpolator(interpolator); 491baa23274596246d03741457701ac515a73aa8818Selim Cinek float durationFactor = Math.abs(mArrowAlpha - targetAlpha); 492baa23274596246d03741457701ac515a73aa8818Selim Cinek long duration = (long) (NORMAL_ANIMATION_DURATION * durationFactor); 493baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.setDuration(duration); 494baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.start(); 495baa23274596246d03741457701ac515a73aa8818Selim Cinek } 496baa23274596246d03741457701ac515a73aa8818Selim Cinek 497baa23274596246d03741457701ac515a73aa8818Selim Cinek public void setIsLeft(boolean left) { 498baa23274596246d03741457701ac515a73aa8818Selim Cinek mIsLeft = left; 499baa23274596246d03741457701ac515a73aa8818Selim Cinek } 50038fc7606b1d8869cd79a19f324bbcd97ba320994Adrian Roos 50138fc7606b1d8869cd79a19f324bbcd97ba320994Adrian Roos @Override 50238fc7606b1d8869cd79a19f324bbcd97ba320994Adrian Roos public boolean performClick() { 50338fc7606b1d8869cd79a19f324bbcd97ba320994Adrian Roos if (isClickable()) { 50438fc7606b1d8869cd79a19f324bbcd97ba320994Adrian Roos return super.performClick(); 50538fc7606b1d8869cd79a19f324bbcd97ba320994Adrian Roos } else { 50638fc7606b1d8869cd79a19f324bbcd97ba320994Adrian Roos return false; 50738fc7606b1d8869cd79a19f324bbcd97ba320994Adrian Roos } 50838fc7606b1d8869cd79a19f324bbcd97ba320994Adrian Roos } 509baa23274596246d03741457701ac515a73aa8818Selim Cinek} 510