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; 2672bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinekimport android.graphics.CanvasProperty; 27baa23274596246d03741457701ac515a73aa8818Selim Cinekimport android.graphics.Color; 28baa23274596246d03741457701ac515a73aa8818Selim Cinekimport android.graphics.Paint; 29baa23274596246d03741457701ac515a73aa8818Selim Cinekimport android.graphics.PorterDuff; 30baa23274596246d03741457701ac515a73aa8818Selim Cinekimport android.graphics.drawable.Drawable; 31baa23274596246d03741457701ac515a73aa8818Selim Cinekimport android.util.AttributeSet; 3272bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinekimport android.view.DisplayListCanvas; 3372bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinekimport android.view.RenderNodeAnimator; 34b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggiimport android.view.View; 35b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggiimport android.view.ViewAnimationUtils; 36baa23274596246d03741457701ac515a73aa8818Selim Cinekimport android.view.animation.Interpolator; 37baa23274596246d03741457701ac515a73aa8818Selim Cinekimport android.widget.ImageView; 38372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek 39c0d7058b14c24cd07912f5629c26b39b7b4673d5Winsonimport com.android.systemui.Interpolators; 40baa23274596246d03741457701ac515a73aa8818Selim Cinekimport com.android.systemui.R; 4127c9b7435083c5620bddefa0cce6a056863b4801Jorim Jaggiimport com.android.systemui.statusbar.phone.KeyguardAffordanceHelper; 42baa23274596246d03741457701ac515a73aa8818Selim Cinek 43baa23274596246d03741457701ac515a73aa8818Selim Cinek/** 44baa23274596246d03741457701ac515a73aa8818Selim Cinek * An ImageView which does not have overlapping renderings commands and therefore does not need a 45baa23274596246d03741457701ac515a73aa8818Selim Cinek * layer when alpha is changed. 46baa23274596246d03741457701ac515a73aa8818Selim Cinek */ 47baa23274596246d03741457701ac515a73aa8818Selim Cinekpublic class KeyguardAffordanceView extends ImageView { 48baa23274596246d03741457701ac515a73aa8818Selim Cinek 49baa23274596246d03741457701ac515a73aa8818Selim Cinek private static final long CIRCLE_APPEAR_DURATION = 80; 50baa23274596246d03741457701ac515a73aa8818Selim Cinek private static final long CIRCLE_DISAPPEAR_MAX_DURATION = 200; 51baa23274596246d03741457701ac515a73aa8818Selim Cinek private static final long NORMAL_ANIMATION_DURATION = 200; 52baa23274596246d03741457701ac515a73aa8818Selim Cinek public static final float MAX_ICON_SCALE_AMOUNT = 1.5f; 53baa23274596246d03741457701ac515a73aa8818Selim Cinek public static final float MIN_ICON_SCALE_AMOUNT = 0.8f; 54baa23274596246d03741457701ac515a73aa8818Selim Cinek 55baa23274596246d03741457701ac515a73aa8818Selim Cinek private final int mMinBackgroundRadius; 56baa23274596246d03741457701ac515a73aa8818Selim Cinek private final Paint mCirclePaint; 57baa23274596246d03741457701ac515a73aa8818Selim Cinek private final int mInverseColor; 58baa23274596246d03741457701ac515a73aa8818Selim Cinek private final int mNormalColor; 59baa23274596246d03741457701ac515a73aa8818Selim Cinek private final ArgbEvaluator mColorInterpolator; 60baa23274596246d03741457701ac515a73aa8818Selim Cinek private final FlingAnimationUtils mFlingAnimationUtils; 61baa23274596246d03741457701ac515a73aa8818Selim Cinek private float mCircleRadius; 62baa23274596246d03741457701ac515a73aa8818Selim Cinek private int mCenterX; 63baa23274596246d03741457701ac515a73aa8818Selim Cinek private int mCenterY; 64baa23274596246d03741457701ac515a73aa8818Selim Cinek private ValueAnimator mCircleAnimator; 65baa23274596246d03741457701ac515a73aa8818Selim Cinek private ValueAnimator mAlphaAnimator; 66baa23274596246d03741457701ac515a73aa8818Selim Cinek private ValueAnimator mScaleAnimator; 67baa23274596246d03741457701ac515a73aa8818Selim Cinek private float mCircleStartValue; 68baa23274596246d03741457701ac515a73aa8818Selim Cinek private boolean mCircleWillBeHidden; 69baa23274596246d03741457701ac515a73aa8818Selim Cinek private int[] mTempPoint = new int[2]; 70a4eba9fc35165dc3391fb1b9580341bba7928277Adrian Roos private float mImageScale = 1f; 71baa23274596246d03741457701ac515a73aa8818Selim Cinek private int mCircleColor; 72baa23274596246d03741457701ac515a73aa8818Selim Cinek private boolean mIsLeft; 73b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi private View mPreviewView; 74b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi private float mCircleStartRadius; 75b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi private float mMaxCircleSize; 76b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi private Animator mPreviewClipper; 7727c9b7435083c5620bddefa0cce6a056863b4801Jorim Jaggi private float mRestingAlpha = KeyguardAffordanceHelper.SWIPE_RESTING_ALPHA_AMOUNT; 7872bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek private boolean mSupportHardware; 7972bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek private boolean mFinishing; 80372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek private boolean mLaunchingAffordance; 8172bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek 8272bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek private CanvasProperty<Float> mHwCircleRadius; 8372bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek private CanvasProperty<Float> mHwCenterX; 8472bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek private CanvasProperty<Float> mHwCenterY; 8572bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek private CanvasProperty<Paint> mHwCirclePaint; 8672bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek 87b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi private AnimatorListenerAdapter mClipEndListener = new AnimatorListenerAdapter() { 88b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi @Override 89b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi public void onAnimationEnd(Animator animation) { 90b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mPreviewClipper = null; 91b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi } 92b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi }; 93baa23274596246d03741457701ac515a73aa8818Selim Cinek private AnimatorListenerAdapter mCircleEndListener = new AnimatorListenerAdapter() { 94baa23274596246d03741457701ac515a73aa8818Selim Cinek @Override 95baa23274596246d03741457701ac515a73aa8818Selim Cinek public void onAnimationEnd(Animator animation) { 96baa23274596246d03741457701ac515a73aa8818Selim Cinek mCircleAnimator = null; 97baa23274596246d03741457701ac515a73aa8818Selim Cinek } 98baa23274596246d03741457701ac515a73aa8818Selim Cinek }; 99baa23274596246d03741457701ac515a73aa8818Selim Cinek private AnimatorListenerAdapter mScaleEndListener = new AnimatorListenerAdapter() { 100baa23274596246d03741457701ac515a73aa8818Selim Cinek @Override 101baa23274596246d03741457701ac515a73aa8818Selim Cinek public void onAnimationEnd(Animator animation) { 102baa23274596246d03741457701ac515a73aa8818Selim Cinek mScaleAnimator = null; 103baa23274596246d03741457701ac515a73aa8818Selim Cinek } 104baa23274596246d03741457701ac515a73aa8818Selim Cinek }; 105baa23274596246d03741457701ac515a73aa8818Selim Cinek private AnimatorListenerAdapter mAlphaEndListener = new AnimatorListenerAdapter() { 106baa23274596246d03741457701ac515a73aa8818Selim Cinek @Override 107baa23274596246d03741457701ac515a73aa8818Selim Cinek public void onAnimationEnd(Animator animation) { 108baa23274596246d03741457701ac515a73aa8818Selim Cinek mAlphaAnimator = null; 109baa23274596246d03741457701ac515a73aa8818Selim Cinek } 110baa23274596246d03741457701ac515a73aa8818Selim Cinek }; 111baa23274596246d03741457701ac515a73aa8818Selim Cinek 112baa23274596246d03741457701ac515a73aa8818Selim Cinek public KeyguardAffordanceView(Context context) { 113baa23274596246d03741457701ac515a73aa8818Selim Cinek this(context, null); 114baa23274596246d03741457701ac515a73aa8818Selim Cinek } 115baa23274596246d03741457701ac515a73aa8818Selim Cinek 116baa23274596246d03741457701ac515a73aa8818Selim Cinek public KeyguardAffordanceView(Context context, AttributeSet attrs) { 117baa23274596246d03741457701ac515a73aa8818Selim Cinek this(context, attrs, 0); 118baa23274596246d03741457701ac515a73aa8818Selim Cinek } 119baa23274596246d03741457701ac515a73aa8818Selim Cinek 120baa23274596246d03741457701ac515a73aa8818Selim Cinek public KeyguardAffordanceView(Context context, AttributeSet attrs, int defStyleAttr) { 121baa23274596246d03741457701ac515a73aa8818Selim Cinek this(context, attrs, defStyleAttr, 0); 122baa23274596246d03741457701ac515a73aa8818Selim Cinek } 123baa23274596246d03741457701ac515a73aa8818Selim Cinek 124baa23274596246d03741457701ac515a73aa8818Selim Cinek public KeyguardAffordanceView(Context context, AttributeSet attrs, int defStyleAttr, 125baa23274596246d03741457701ac515a73aa8818Selim Cinek int defStyleRes) { 126baa23274596246d03741457701ac515a73aa8818Selim Cinek super(context, attrs, defStyleAttr, defStyleRes); 127baa23274596246d03741457701ac515a73aa8818Selim Cinek mCirclePaint = new Paint(); 128baa23274596246d03741457701ac515a73aa8818Selim Cinek mCirclePaint.setAntiAlias(true); 129baa23274596246d03741457701ac515a73aa8818Selim Cinek mCircleColor = 0xffffffff; 130baa23274596246d03741457701ac515a73aa8818Selim Cinek mCirclePaint.setColor(mCircleColor); 131baa23274596246d03741457701ac515a73aa8818Selim Cinek 132baa23274596246d03741457701ac515a73aa8818Selim Cinek mNormalColor = 0xffffffff; 133baa23274596246d03741457701ac515a73aa8818Selim Cinek mInverseColor = 0xff000000; 134baa23274596246d03741457701ac515a73aa8818Selim Cinek mMinBackgroundRadius = mContext.getResources().getDimensionPixelSize( 135baa23274596246d03741457701ac515a73aa8818Selim Cinek R.dimen.keyguard_affordance_min_background_radius); 136baa23274596246d03741457701ac515a73aa8818Selim Cinek mColorInterpolator = new ArgbEvaluator(); 137baa23274596246d03741457701ac515a73aa8818Selim Cinek mFlingAnimationUtils = new FlingAnimationUtils(mContext, 0.3f); 138baa23274596246d03741457701ac515a73aa8818Selim Cinek } 139baa23274596246d03741457701ac515a73aa8818Selim Cinek 140baa23274596246d03741457701ac515a73aa8818Selim Cinek @Override 141baa23274596246d03741457701ac515a73aa8818Selim Cinek protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 142baa23274596246d03741457701ac515a73aa8818Selim Cinek super.onLayout(changed, left, top, right, bottom); 143baa23274596246d03741457701ac515a73aa8818Selim Cinek mCenterX = getWidth() / 2; 144baa23274596246d03741457701ac515a73aa8818Selim Cinek mCenterY = getHeight() / 2; 145b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mMaxCircleSize = getMaxCircleSize(); 146baa23274596246d03741457701ac515a73aa8818Selim Cinek } 147baa23274596246d03741457701ac515a73aa8818Selim Cinek 148baa23274596246d03741457701ac515a73aa8818Selim Cinek @Override 149baa23274596246d03741457701ac515a73aa8818Selim Cinek protected void onDraw(Canvas canvas) { 1504ae263c87c0a55613d34738aa2b44ccec4eb75ffSelim Cinek mSupportHardware = canvas.isHardwareAccelerated(); 151baa23274596246d03741457701ac515a73aa8818Selim Cinek drawBackgroundCircle(canvas); 152baa23274596246d03741457701ac515a73aa8818Selim Cinek canvas.save(); 153baa23274596246d03741457701ac515a73aa8818Selim Cinek canvas.scale(mImageScale, mImageScale, getWidth() / 2, getHeight() / 2); 154baa23274596246d03741457701ac515a73aa8818Selim Cinek super.onDraw(canvas); 155baa23274596246d03741457701ac515a73aa8818Selim Cinek canvas.restore(); 156baa23274596246d03741457701ac515a73aa8818Selim Cinek } 157baa23274596246d03741457701ac515a73aa8818Selim Cinek 158b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi public void setPreviewView(View v) { 159372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek View oldPreviewView = mPreviewView; 160b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mPreviewView = v; 1610d61b51852278de763d971ae0c57b27e6ed1ce6aSelim Cinek if (mPreviewView != null) { 162372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek mPreviewView.setVisibility(mLaunchingAffordance 163372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek ? oldPreviewView.getVisibility() : INVISIBLE); 1640d61b51852278de763d971ae0c57b27e6ed1ce6aSelim Cinek } 165b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi } 166b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi 167baa23274596246d03741457701ac515a73aa8818Selim Cinek private void updateIconColor() { 168baa23274596246d03741457701ac515a73aa8818Selim Cinek Drawable drawable = getDrawable().mutate(); 169baa23274596246d03741457701ac515a73aa8818Selim Cinek float alpha = mCircleRadius / mMinBackgroundRadius; 170baa23274596246d03741457701ac515a73aa8818Selim Cinek alpha = Math.min(1.0f, alpha); 171baa23274596246d03741457701ac515a73aa8818Selim Cinek int color = (int) mColorInterpolator.evaluate(alpha, mNormalColor, mInverseColor); 172baa23274596246d03741457701ac515a73aa8818Selim Cinek drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP); 173baa23274596246d03741457701ac515a73aa8818Selim Cinek } 174baa23274596246d03741457701ac515a73aa8818Selim Cinek 175baa23274596246d03741457701ac515a73aa8818Selim Cinek private void drawBackgroundCircle(Canvas canvas) { 176372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek if (mCircleRadius > 0 || mFinishing) { 1772c984f16eb4afc3455482cfbf3e8b03c97189bcaSelim Cinek if (mFinishing && mSupportHardware && mHwCenterX != null) { 1782c984f16eb4afc3455482cfbf3e8b03c97189bcaSelim Cinek // Our hardware drawing proparties can be null if the finishing started but we have 1792c984f16eb4afc3455482cfbf3e8b03c97189bcaSelim Cinek // never drawn before. In that case we are not doing a render thread animation 1802c984f16eb4afc3455482cfbf3e8b03c97189bcaSelim Cinek // anyway, so we need to use the normal drawing. 18172bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas; 18272bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek displayListCanvas.drawCircle(mHwCenterX, mHwCenterY, mHwCircleRadius, 18372bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek mHwCirclePaint); 18472bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek } else { 18572bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek updateCircleColor(); 18672bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek canvas.drawCircle(mCenterX, mCenterY, mCircleRadius, mCirclePaint); 18772bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek } 188baa23274596246d03741457701ac515a73aa8818Selim Cinek } 189baa23274596246d03741457701ac515a73aa8818Selim Cinek } 190baa23274596246d03741457701ac515a73aa8818Selim Cinek 191baa23274596246d03741457701ac515a73aa8818Selim Cinek private void updateCircleColor() { 192baa23274596246d03741457701ac515a73aa8818Selim Cinek float fraction = 0.5f + 0.5f * Math.max(0.0f, Math.min(1.0f, 193baa23274596246d03741457701ac515a73aa8818Selim Cinek (mCircleRadius - mMinBackgroundRadius) / (0.5f * mMinBackgroundRadius))); 1946746c28b812446e847fbfec0f54025558584e70aSelim Cinek if (mPreviewView != null && mPreviewView.getVisibility() == VISIBLE) { 195b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi float finishingFraction = 1 - Math.max(0, mCircleRadius - mCircleStartRadius) 196b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi / (mMaxCircleSize - mCircleStartRadius); 197b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi fraction *= finishingFraction; 198b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi } 199baa23274596246d03741457701ac515a73aa8818Selim Cinek int color = Color.argb((int) (Color.alpha(mCircleColor) * fraction), 200baa23274596246d03741457701ac515a73aa8818Selim Cinek Color.red(mCircleColor), 201baa23274596246d03741457701ac515a73aa8818Selim Cinek Color.green(mCircleColor), Color.blue(mCircleColor)); 202baa23274596246d03741457701ac515a73aa8818Selim Cinek mCirclePaint.setColor(color); 203baa23274596246d03741457701ac515a73aa8818Selim Cinek } 204baa23274596246d03741457701ac515a73aa8818Selim Cinek 205baa23274596246d03741457701ac515a73aa8818Selim Cinek public void finishAnimation(float velocity, final Runnable mAnimationEndRunnable) { 206baa23274596246d03741457701ac515a73aa8818Selim Cinek cancelAnimator(mCircleAnimator); 207b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi cancelAnimator(mPreviewClipper); 20872bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek mFinishing = true; 209b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mCircleStartRadius = mCircleRadius; 210372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek final float maxCircleSize = getMaxCircleSize(); 21172bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek Animator animatorToRadius; 21272bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek if (mSupportHardware) { 21372bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek initHwProperties(); 21472bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek animatorToRadius = getRtAnimatorToRadius(maxCircleSize); 215372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek startRtAlphaFadeIn(); 21672bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek } else { 21772bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek animatorToRadius = getAnimatorToRadius(maxCircleSize); 21872bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek } 219baa23274596246d03741457701ac515a73aa8818Selim Cinek mFlingAnimationUtils.applyDismissing(animatorToRadius, mCircleRadius, maxCircleSize, 220baa23274596246d03741457701ac515a73aa8818Selim Cinek velocity, maxCircleSize); 221baa23274596246d03741457701ac515a73aa8818Selim Cinek animatorToRadius.addListener(new AnimatorListenerAdapter() { 222baa23274596246d03741457701ac515a73aa8818Selim Cinek @Override 223baa23274596246d03741457701ac515a73aa8818Selim Cinek public void onAnimationEnd(Animator animation) { 224baa23274596246d03741457701ac515a73aa8818Selim Cinek mAnimationEndRunnable.run(); 22572bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek mFinishing = false; 226372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek mCircleRadius = maxCircleSize; 227372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek invalidate(); 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(); 24172bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek if (mSupportHardware) { 24272bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek startRtCircleFadeOut(animatorToRadius.getDuration()); 24372bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek } 244b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi } 245baa23274596246d03741457701ac515a73aa8818Selim Cinek } 246baa23274596246d03741457701ac515a73aa8818Selim Cinek 247372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek /** 248372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek * Fades in the Circle on the RenderThread. It's used when finishing the circle when it had 249372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek * alpha 0 in the beginning. 250372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek */ 251372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek private void startRtAlphaFadeIn() { 252372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek if (mCircleRadius == 0 && mPreviewView == null) { 253372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek Paint modifiedPaint = new Paint(mCirclePaint); 254372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek modifiedPaint.setColor(mCircleColor); 255372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek modifiedPaint.setAlpha(0); 256372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek mHwCirclePaint = CanvasProperty.createPaint(modifiedPaint); 257372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek RenderNodeAnimator animator = new RenderNodeAnimator(mHwCirclePaint, 258372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek RenderNodeAnimator.PAINT_ALPHA, 255); 259372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek animator.setTarget(this); 260c18010f6720f606003cde3cd376ddacaca30f6e5Selim Cinek animator.setInterpolator(Interpolators.ALPHA_IN); 261372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek animator.setDuration(250); 262372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek animator.start(); 263372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek } 264372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek } 265372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek 266372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek public void instantFinishAnimation() { 267372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek cancelAnimator(mPreviewClipper); 268372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek if (mPreviewView != null) { 269372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek mPreviewView.setClipBounds(null); 270372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek mPreviewView.setVisibility(View.VISIBLE); 271372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek } 272372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek mCircleRadius = getMaxCircleSize(); 273372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek setImageAlpha(0, false); 274372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek invalidate(); 275372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek } 276372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek 27772bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek private void startRtCircleFadeOut(long duration) { 27872bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek RenderNodeAnimator animator = new RenderNodeAnimator(mHwCirclePaint, 27972bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek RenderNodeAnimator.PAINT_ALPHA, 0); 28072bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek animator.setDuration(duration); 281c18010f6720f606003cde3cd376ddacaca30f6e5Selim Cinek animator.setInterpolator(Interpolators.ALPHA_OUT); 28272bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek animator.setTarget(this); 28372bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek animator.start(); 28472bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek } 28572bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek 28672bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek private Animator getRtAnimatorToRadius(float circleRadius) { 28772bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek RenderNodeAnimator animator = new RenderNodeAnimator(mHwCircleRadius, circleRadius); 28872bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek animator.setTarget(this); 28972bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek return animator; 29072bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek } 29172bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek 29272bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek private void initHwProperties() { 29372bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek mHwCenterX = CanvasProperty.createFloat(mCenterX); 29472bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek mHwCenterY = CanvasProperty.createFloat(mCenterY); 29572bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek mHwCirclePaint = CanvasProperty.createPaint(mCirclePaint); 29672bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek mHwCircleRadius = CanvasProperty.createFloat(mCircleRadius); 29772bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek } 29872bcaa20afab21eedf749c7a4bdb807dd41b06f8Selim Cinek 299baa23274596246d03741457701ac515a73aa8818Selim Cinek private float getMaxCircleSize() { 300baa23274596246d03741457701ac515a73aa8818Selim Cinek getLocationInWindow(mTempPoint); 301baa23274596246d03741457701ac515a73aa8818Selim Cinek float rootWidth = getRootView().getWidth(); 302baa23274596246d03741457701ac515a73aa8818Selim Cinek float width = mTempPoint[0] + mCenterX; 303baa23274596246d03741457701ac515a73aa8818Selim Cinek width = Math.max(rootWidth - width, width); 304baa23274596246d03741457701ac515a73aa8818Selim Cinek float height = mTempPoint[1] + mCenterY; 305baa23274596246d03741457701ac515a73aa8818Selim Cinek return (float) Math.hypot(width, height); 306baa23274596246d03741457701ac515a73aa8818Selim Cinek } 307baa23274596246d03741457701ac515a73aa8818Selim Cinek 308baa23274596246d03741457701ac515a73aa8818Selim Cinek public void setCircleRadius(float circleRadius) { 3095386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek setCircleRadius(circleRadius, false, false); 3105386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek } 3115386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek 3125386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek public void setCircleRadius(float circleRadius, boolean slowAnimation) { 3135386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek setCircleRadius(circleRadius, slowAnimation, false); 314baa23274596246d03741457701ac515a73aa8818Selim Cinek } 315baa23274596246d03741457701ac515a73aa8818Selim Cinek 316baa23274596246d03741457701ac515a73aa8818Selim Cinek public void setCircleRadiusWithoutAnimation(float circleRadius) { 317baa23274596246d03741457701ac515a73aa8818Selim Cinek cancelAnimator(mCircleAnimator); 3185386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek setCircleRadius(circleRadius, false ,true); 319baa23274596246d03741457701ac515a73aa8818Selim Cinek } 320baa23274596246d03741457701ac515a73aa8818Selim Cinek 3215386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek private void setCircleRadius(float circleRadius, boolean slowAnimation, boolean noAnimation) { 322baa23274596246d03741457701ac515a73aa8818Selim Cinek 323baa23274596246d03741457701ac515a73aa8818Selim Cinek // Check if we need a new animation 324baa23274596246d03741457701ac515a73aa8818Selim Cinek boolean radiusHidden = (mCircleAnimator != null && mCircleWillBeHidden) 325baa23274596246d03741457701ac515a73aa8818Selim Cinek || (mCircleAnimator == null && mCircleRadius == 0.0f); 326baa23274596246d03741457701ac515a73aa8818Selim Cinek boolean nowHidden = circleRadius == 0.0f; 327baa23274596246d03741457701ac515a73aa8818Selim Cinek boolean radiusNeedsAnimation = (radiusHidden != nowHidden) && !noAnimation; 328baa23274596246d03741457701ac515a73aa8818Selim Cinek if (!radiusNeedsAnimation) { 329baa23274596246d03741457701ac515a73aa8818Selim Cinek if (mCircleAnimator == null) { 330baa23274596246d03741457701ac515a73aa8818Selim Cinek mCircleRadius = circleRadius; 3310b75f83f142a4de5be77238c6030228e1b943aa2Jorim Jaggi updateIconColor(); 332baa23274596246d03741457701ac515a73aa8818Selim Cinek invalidate(); 333b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi if (nowHidden) { 334b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi if (mPreviewView != null) { 335b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mPreviewView.setVisibility(View.INVISIBLE); 336b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi } 337b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi } 338baa23274596246d03741457701ac515a73aa8818Selim Cinek } else if (!mCircleWillBeHidden) { 339baa23274596246d03741457701ac515a73aa8818Selim Cinek 340baa23274596246d03741457701ac515a73aa8818Selim Cinek // We just update the end value 341baa23274596246d03741457701ac515a73aa8818Selim Cinek float diff = circleRadius - mMinBackgroundRadius; 342baa23274596246d03741457701ac515a73aa8818Selim Cinek PropertyValuesHolder[] values = mCircleAnimator.getValues(); 343baa23274596246d03741457701ac515a73aa8818Selim Cinek values[0].setFloatValues(mCircleStartValue + diff, circleRadius); 344baa23274596246d03741457701ac515a73aa8818Selim Cinek mCircleAnimator.setCurrentPlayTime(mCircleAnimator.getCurrentPlayTime()); 345baa23274596246d03741457701ac515a73aa8818Selim Cinek } 346baa23274596246d03741457701ac515a73aa8818Selim Cinek } else { 347baa23274596246d03741457701ac515a73aa8818Selim Cinek cancelAnimator(mCircleAnimator); 348b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi cancelAnimator(mPreviewClipper); 349baa23274596246d03741457701ac515a73aa8818Selim Cinek ValueAnimator animator = getAnimatorToRadius(circleRadius); 350baa23274596246d03741457701ac515a73aa8818Selim Cinek Interpolator interpolator = circleRadius == 0.0f 351c18010f6720f606003cde3cd376ddacaca30f6e5Selim Cinek ? Interpolators.FAST_OUT_LINEAR_IN 352c18010f6720f606003cde3cd376ddacaca30f6e5Selim Cinek : Interpolators.LINEAR_OUT_SLOW_IN; 353baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.setInterpolator(interpolator); 3545386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek long duration = 250; 3555386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek if (!slowAnimation) { 3565386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek float durationFactor = Math.abs(mCircleRadius - circleRadius) 3575386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek / (float) mMinBackgroundRadius; 3585386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek duration = (long) (CIRCLE_APPEAR_DURATION * durationFactor); 3595386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek duration = Math.min(duration, CIRCLE_DISAPPEAR_MAX_DURATION); 3605386fb337d3f2bd9b0ea673b5f60483246e5d0cdSelim Cinek } 361baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.setDuration(duration); 362baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.start(); 3630d61b51852278de763d971ae0c57b27e6ed1ce6aSelim Cinek if (mPreviewView != null && mPreviewView.getVisibility() == View.VISIBLE) { 364b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mPreviewView.setVisibility(View.VISIBLE); 365b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mPreviewClipper = ViewAnimationUtils.createCircularReveal( 366b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mPreviewView, getLeft() + mCenterX, getTop() + mCenterY, mCircleRadius, 367b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi circleRadius); 368b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mPreviewClipper.setInterpolator(interpolator); 369b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mPreviewClipper.setDuration(duration); 370b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mPreviewClipper.addListener(mClipEndListener); 371b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mPreviewClipper.addListener(new AnimatorListenerAdapter() { 372b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi @Override 373b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi public void onAnimationEnd(Animator animation) { 374b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mPreviewView.setVisibility(View.INVISIBLE); 375b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi } 376b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi }); 377b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi mPreviewClipper.start(); 378b6cdcbc66b4b862f83afde85b8e7109b6450b15eJorim Jaggi } 379baa23274596246d03741457701ac515a73aa8818Selim Cinek } 380baa23274596246d03741457701ac515a73aa8818Selim Cinek } 381baa23274596246d03741457701ac515a73aa8818Selim Cinek 382baa23274596246d03741457701ac515a73aa8818Selim Cinek private ValueAnimator getAnimatorToRadius(float circleRadius) { 383baa23274596246d03741457701ac515a73aa8818Selim Cinek ValueAnimator animator = ValueAnimator.ofFloat(mCircleRadius, circleRadius); 384baa23274596246d03741457701ac515a73aa8818Selim Cinek mCircleAnimator = animator; 385baa23274596246d03741457701ac515a73aa8818Selim Cinek mCircleStartValue = mCircleRadius; 386baa23274596246d03741457701ac515a73aa8818Selim Cinek mCircleWillBeHidden = circleRadius == 0.0f; 387baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 388baa23274596246d03741457701ac515a73aa8818Selim Cinek @Override 389baa23274596246d03741457701ac515a73aa8818Selim Cinek public void onAnimationUpdate(ValueAnimator animation) { 390baa23274596246d03741457701ac515a73aa8818Selim Cinek mCircleRadius = (float) animation.getAnimatedValue(); 3910b75f83f142a4de5be77238c6030228e1b943aa2Jorim Jaggi updateIconColor(); 392baa23274596246d03741457701ac515a73aa8818Selim Cinek invalidate(); 393baa23274596246d03741457701ac515a73aa8818Selim Cinek } 394baa23274596246d03741457701ac515a73aa8818Selim Cinek }); 395baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.addListener(mCircleEndListener); 396baa23274596246d03741457701ac515a73aa8818Selim Cinek return animator; 397baa23274596246d03741457701ac515a73aa8818Selim Cinek } 398baa23274596246d03741457701ac515a73aa8818Selim Cinek 399baa23274596246d03741457701ac515a73aa8818Selim Cinek private void cancelAnimator(Animator animator) { 400baa23274596246d03741457701ac515a73aa8818Selim Cinek if (animator != null) { 401baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.cancel(); 402baa23274596246d03741457701ac515a73aa8818Selim Cinek } 403baa23274596246d03741457701ac515a73aa8818Selim Cinek } 404baa23274596246d03741457701ac515a73aa8818Selim Cinek 405baa23274596246d03741457701ac515a73aa8818Selim Cinek public void setImageScale(float imageScale, boolean animate) { 406baa23274596246d03741457701ac515a73aa8818Selim Cinek setImageScale(imageScale, animate, -1, null); 407baa23274596246d03741457701ac515a73aa8818Selim Cinek } 408baa23274596246d03741457701ac515a73aa8818Selim Cinek 409baa23274596246d03741457701ac515a73aa8818Selim Cinek /** 410baa23274596246d03741457701ac515a73aa8818Selim Cinek * Sets the scale of the containing image 411baa23274596246d03741457701ac515a73aa8818Selim Cinek * 412baa23274596246d03741457701ac515a73aa8818Selim Cinek * @param imageScale The new Scale. 413baa23274596246d03741457701ac515a73aa8818Selim Cinek * @param animate Should an animation be performed 414baa23274596246d03741457701ac515a73aa8818Selim Cinek * @param duration If animate, whats the duration? When -1 we take the default duration 415baa23274596246d03741457701ac515a73aa8818Selim Cinek * @param interpolator If animate, whats the interpolator? When null we take the default 416baa23274596246d03741457701ac515a73aa8818Selim Cinek * interpolator. 417baa23274596246d03741457701ac515a73aa8818Selim Cinek */ 418baa23274596246d03741457701ac515a73aa8818Selim Cinek public void setImageScale(float imageScale, boolean animate, long duration, 419baa23274596246d03741457701ac515a73aa8818Selim Cinek Interpolator interpolator) { 420baa23274596246d03741457701ac515a73aa8818Selim Cinek cancelAnimator(mScaleAnimator); 421baa23274596246d03741457701ac515a73aa8818Selim Cinek if (!animate) { 422baa23274596246d03741457701ac515a73aa8818Selim Cinek mImageScale = imageScale; 423baa23274596246d03741457701ac515a73aa8818Selim Cinek invalidate(); 424baa23274596246d03741457701ac515a73aa8818Selim Cinek } else { 425baa23274596246d03741457701ac515a73aa8818Selim Cinek ValueAnimator animator = ValueAnimator.ofFloat(mImageScale, imageScale); 426baa23274596246d03741457701ac515a73aa8818Selim Cinek mScaleAnimator = animator; 427baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 428baa23274596246d03741457701ac515a73aa8818Selim Cinek @Override 429baa23274596246d03741457701ac515a73aa8818Selim Cinek public void onAnimationUpdate(ValueAnimator animation) { 430baa23274596246d03741457701ac515a73aa8818Selim Cinek mImageScale = (float) animation.getAnimatedValue(); 431baa23274596246d03741457701ac515a73aa8818Selim Cinek invalidate(); 432baa23274596246d03741457701ac515a73aa8818Selim Cinek } 433baa23274596246d03741457701ac515a73aa8818Selim Cinek }); 434baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.addListener(mScaleEndListener); 435baa23274596246d03741457701ac515a73aa8818Selim Cinek if (interpolator == null) { 436baa23274596246d03741457701ac515a73aa8818Selim Cinek interpolator = imageScale == 0.0f 437c18010f6720f606003cde3cd376ddacaca30f6e5Selim Cinek ? Interpolators.FAST_OUT_LINEAR_IN 438c18010f6720f606003cde3cd376ddacaca30f6e5Selim Cinek : Interpolators.LINEAR_OUT_SLOW_IN; 439baa23274596246d03741457701ac515a73aa8818Selim Cinek } 440baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.setInterpolator(interpolator); 441baa23274596246d03741457701ac515a73aa8818Selim Cinek if (duration == -1) { 442baa23274596246d03741457701ac515a73aa8818Selim Cinek float durationFactor = Math.abs(mImageScale - imageScale) 443baa23274596246d03741457701ac515a73aa8818Selim Cinek / (1.0f - MIN_ICON_SCALE_AMOUNT); 444baa23274596246d03741457701ac515a73aa8818Selim Cinek durationFactor = Math.min(1.0f, durationFactor); 445baa23274596246d03741457701ac515a73aa8818Selim Cinek duration = (long) (NORMAL_ANIMATION_DURATION * durationFactor); 446baa23274596246d03741457701ac515a73aa8818Selim Cinek } 447baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.setDuration(duration); 448baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.start(); 449baa23274596246d03741457701ac515a73aa8818Selim Cinek } 450baa23274596246d03741457701ac515a73aa8818Selim Cinek } 451baa23274596246d03741457701ac515a73aa8818Selim Cinek 45227c9b7435083c5620bddefa0cce6a056863b4801Jorim Jaggi public void setRestingAlpha(float alpha) { 45327c9b7435083c5620bddefa0cce6a056863b4801Jorim Jaggi mRestingAlpha = alpha; 45427c9b7435083c5620bddefa0cce6a056863b4801Jorim Jaggi 45527c9b7435083c5620bddefa0cce6a056863b4801Jorim Jaggi // TODO: Handle the case an animation is playing. 45627c9b7435083c5620bddefa0cce6a056863b4801Jorim Jaggi setImageAlpha(alpha, false); 45727c9b7435083c5620bddefa0cce6a056863b4801Jorim Jaggi } 45827c9b7435083c5620bddefa0cce6a056863b4801Jorim Jaggi 45927c9b7435083c5620bddefa0cce6a056863b4801Jorim Jaggi public float getRestingAlpha() { 46027c9b7435083c5620bddefa0cce6a056863b4801Jorim Jaggi return mRestingAlpha; 46127c9b7435083c5620bddefa0cce6a056863b4801Jorim Jaggi } 46227c9b7435083c5620bddefa0cce6a056863b4801Jorim Jaggi 463baa23274596246d03741457701ac515a73aa8818Selim Cinek public void setImageAlpha(float alpha, boolean animate) { 464baa23274596246d03741457701ac515a73aa8818Selim Cinek setImageAlpha(alpha, animate, -1, null, null); 465baa23274596246d03741457701ac515a73aa8818Selim Cinek } 466baa23274596246d03741457701ac515a73aa8818Selim Cinek 467baa23274596246d03741457701ac515a73aa8818Selim Cinek /** 468baa23274596246d03741457701ac515a73aa8818Selim Cinek * Sets the alpha of the containing image 469baa23274596246d03741457701ac515a73aa8818Selim Cinek * 470baa23274596246d03741457701ac515a73aa8818Selim Cinek * @param alpha The new alpha. 471baa23274596246d03741457701ac515a73aa8818Selim Cinek * @param animate Should an animation be performed 472baa23274596246d03741457701ac515a73aa8818Selim Cinek * @param duration If animate, whats the duration? When -1 we take the default duration 473baa23274596246d03741457701ac515a73aa8818Selim Cinek * @param interpolator If animate, whats the interpolator? When null we take the default 474baa23274596246d03741457701ac515a73aa8818Selim Cinek * interpolator. 475baa23274596246d03741457701ac515a73aa8818Selim Cinek */ 476baa23274596246d03741457701ac515a73aa8818Selim Cinek public void setImageAlpha(float alpha, boolean animate, long duration, 477baa23274596246d03741457701ac515a73aa8818Selim Cinek Interpolator interpolator, Runnable runnable) { 478baa23274596246d03741457701ac515a73aa8818Selim Cinek cancelAnimator(mAlphaAnimator); 479372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek alpha = mLaunchingAffordance ? 0 : alpha; 480baa23274596246d03741457701ac515a73aa8818Selim Cinek int endAlpha = (int) (alpha * 255); 4814ebcdfdd4294cc52a68fb150bc7a34f005290ea3Adrian Roos final Drawable background = getBackground(); 482baa23274596246d03741457701ac515a73aa8818Selim Cinek if (!animate) { 4834ebcdfdd4294cc52a68fb150bc7a34f005290ea3Adrian Roos if (background != null) background.mutate().setAlpha(endAlpha); 484baa23274596246d03741457701ac515a73aa8818Selim Cinek setImageAlpha(endAlpha); 485baa23274596246d03741457701ac515a73aa8818Selim Cinek } else { 486baa23274596246d03741457701ac515a73aa8818Selim Cinek int currentAlpha = getImageAlpha(); 487baa23274596246d03741457701ac515a73aa8818Selim Cinek ValueAnimator animator = ValueAnimator.ofInt(currentAlpha, endAlpha); 488baa23274596246d03741457701ac515a73aa8818Selim Cinek mAlphaAnimator = animator; 489baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 490baa23274596246d03741457701ac515a73aa8818Selim Cinek @Override 491baa23274596246d03741457701ac515a73aa8818Selim Cinek public void onAnimationUpdate(ValueAnimator animation) { 4924ebcdfdd4294cc52a68fb150bc7a34f005290ea3Adrian Roos int alpha = (int) animation.getAnimatedValue(); 4934ebcdfdd4294cc52a68fb150bc7a34f005290ea3Adrian Roos if (background != null) background.mutate().setAlpha(alpha); 4944ebcdfdd4294cc52a68fb150bc7a34f005290ea3Adrian Roos setImageAlpha(alpha); 495baa23274596246d03741457701ac515a73aa8818Selim Cinek } 496baa23274596246d03741457701ac515a73aa8818Selim Cinek }); 497baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.addListener(mAlphaEndListener); 498baa23274596246d03741457701ac515a73aa8818Selim Cinek if (interpolator == null) { 499baa23274596246d03741457701ac515a73aa8818Selim Cinek interpolator = alpha == 0.0f 500c18010f6720f606003cde3cd376ddacaca30f6e5Selim Cinek ? Interpolators.FAST_OUT_LINEAR_IN 501c18010f6720f606003cde3cd376ddacaca30f6e5Selim Cinek : Interpolators.LINEAR_OUT_SLOW_IN; 502baa23274596246d03741457701ac515a73aa8818Selim Cinek } 503baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.setInterpolator(interpolator); 504baa23274596246d03741457701ac515a73aa8818Selim Cinek if (duration == -1) { 505baa23274596246d03741457701ac515a73aa8818Selim Cinek float durationFactor = Math.abs(currentAlpha - endAlpha) / 255f; 506baa23274596246d03741457701ac515a73aa8818Selim Cinek durationFactor = Math.min(1.0f, durationFactor); 507baa23274596246d03741457701ac515a73aa8818Selim Cinek duration = (long) (NORMAL_ANIMATION_DURATION * durationFactor); 508baa23274596246d03741457701ac515a73aa8818Selim Cinek } 509baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.setDuration(duration); 510baa23274596246d03741457701ac515a73aa8818Selim Cinek if (runnable != null) { 511baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.addListener(getEndListener(runnable)); 512baa23274596246d03741457701ac515a73aa8818Selim Cinek } 513baa23274596246d03741457701ac515a73aa8818Selim Cinek animator.start(); 514baa23274596246d03741457701ac515a73aa8818Selim Cinek } 515baa23274596246d03741457701ac515a73aa8818Selim Cinek } 516baa23274596246d03741457701ac515a73aa8818Selim Cinek 517baa23274596246d03741457701ac515a73aa8818Selim Cinek private Animator.AnimatorListener getEndListener(final Runnable runnable) { 518baa23274596246d03741457701ac515a73aa8818Selim Cinek return new AnimatorListenerAdapter() { 519baa23274596246d03741457701ac515a73aa8818Selim Cinek boolean mCancelled; 520baa23274596246d03741457701ac515a73aa8818Selim Cinek @Override 521baa23274596246d03741457701ac515a73aa8818Selim Cinek public void onAnimationCancel(Animator animation) { 522baa23274596246d03741457701ac515a73aa8818Selim Cinek mCancelled = true; 523baa23274596246d03741457701ac515a73aa8818Selim Cinek } 524baa23274596246d03741457701ac515a73aa8818Selim Cinek 525baa23274596246d03741457701ac515a73aa8818Selim Cinek @Override 526baa23274596246d03741457701ac515a73aa8818Selim Cinek public void onAnimationEnd(Animator animation) { 527baa23274596246d03741457701ac515a73aa8818Selim Cinek if (!mCancelled) { 528baa23274596246d03741457701ac515a73aa8818Selim Cinek runnable.run(); 529baa23274596246d03741457701ac515a73aa8818Selim Cinek } 530baa23274596246d03741457701ac515a73aa8818Selim Cinek } 531baa23274596246d03741457701ac515a73aa8818Selim Cinek }; 532baa23274596246d03741457701ac515a73aa8818Selim Cinek } 533baa23274596246d03741457701ac515a73aa8818Selim Cinek 534baa23274596246d03741457701ac515a73aa8818Selim Cinek public float getCircleRadius() { 535baa23274596246d03741457701ac515a73aa8818Selim Cinek return mCircleRadius; 536baa23274596246d03741457701ac515a73aa8818Selim Cinek } 537baa23274596246d03741457701ac515a73aa8818Selim Cinek 53838fc7606b1d8869cd79a19f324bbcd97ba320994Adrian Roos @Override 53938fc7606b1d8869cd79a19f324bbcd97ba320994Adrian Roos public boolean performClick() { 54038fc7606b1d8869cd79a19f324bbcd97ba320994Adrian Roos if (isClickable()) { 54138fc7606b1d8869cd79a19f324bbcd97ba320994Adrian Roos return super.performClick(); 54238fc7606b1d8869cd79a19f324bbcd97ba320994Adrian Roos } else { 54338fc7606b1d8869cd79a19f324bbcd97ba320994Adrian Roos return false; 54438fc7606b1d8869cd79a19f324bbcd97ba320994Adrian Roos } 54538fc7606b1d8869cd79a19f324bbcd97ba320994Adrian Roos } 546372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek 547372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek public void setLaunchingAffordance(boolean launchingAffordance) { 548372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek mLaunchingAffordance = launchingAffordance; 549372d1bdd54fe977c71bdaae895687c76ac35202aSelim Cinek } 550baa23274596246d03741457701ac515a73aa8818Selim Cinek} 551