1223622a50db319d634616311ff74267cf49679e7Alan Viverette/* 2223622a50db319d634616311ff74267cf49679e7Alan Viverette * Copyright (C) 2013 The Android Open Source Project 3223622a50db319d634616311ff74267cf49679e7Alan Viverette * 4223622a50db319d634616311ff74267cf49679e7Alan Viverette * Licensed under the Apache License, Version 2.0 (the "License"); 5223622a50db319d634616311ff74267cf49679e7Alan Viverette * you may not use this file except in compliance with the License. 6223622a50db319d634616311ff74267cf49679e7Alan Viverette * You may obtain a copy of the License at 7223622a50db319d634616311ff74267cf49679e7Alan Viverette * 8223622a50db319d634616311ff74267cf49679e7Alan Viverette * http://www.apache.org/licenses/LICENSE-2.0 9223622a50db319d634616311ff74267cf49679e7Alan Viverette * 10223622a50db319d634616311ff74267cf49679e7Alan Viverette * Unless required by applicable law or agreed to in writing, software 11223622a50db319d634616311ff74267cf49679e7Alan Viverette * distributed under the License is distributed on an "AS IS" BASIS, 12223622a50db319d634616311ff74267cf49679e7Alan Viverette * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13223622a50db319d634616311ff74267cf49679e7Alan Viverette * See the License for the specific language governing permissions and 14223622a50db319d634616311ff74267cf49679e7Alan Viverette * limitations under the License. 15223622a50db319d634616311ff74267cf49679e7Alan Viverette */ 16223622a50db319d634616311ff74267cf49679e7Alan Viverette 17223622a50db319d634616311ff74267cf49679e7Alan Viverettepackage android.graphics.drawable; 18223622a50db319d634616311ff74267cf49679e7Alan Viverette 1953d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viveretteimport android.animation.Animator; 20de399397947c5379c61a1003c017b96accbbf545Alan Viveretteimport android.animation.AnimatorListenerAdapter; 2153d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viveretteimport android.animation.ObjectAnimator; 22223622a50db319d634616311ff74267cf49679e7Alan Viveretteimport android.animation.TimeInterpolator; 23223622a50db319d634616311ff74267cf49679e7Alan Viveretteimport android.graphics.Canvas; 24ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viveretteimport android.graphics.CanvasProperty; 25223622a50db319d634616311ff74267cf49679e7Alan Viveretteimport android.graphics.Paint; 26223622a50db319d634616311ff74267cf49679e7Alan Viveretteimport android.graphics.Rect; 274d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viveretteimport android.util.MathUtils; 28ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viveretteimport android.view.HardwareCanvas; 29ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viveretteimport android.view.RenderNodeAnimator; 304d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viveretteimport android.view.animation.LinearInterpolator; 31ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette 32ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viveretteimport java.util.ArrayList; 33223622a50db319d634616311ff74267cf49679e7Alan Viverette 34223622a50db319d634616311ff74267cf49679e7Alan Viverette/** 353cb07a462be293634e6a83ea6c82f3647cd17dadAlan Viverette * Draws a Material ripple. 36223622a50db319d634616311ff74267cf49679e7Alan Viverette */ 37223622a50db319d634616311ff74267cf49679e7Alan Viveretteclass Ripple { 384d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator(); 394b65f0ebee11dd95cd4a03329bfa135ec5582badChristian Robertson private static final TimeInterpolator DECEL_INTERPOLATOR = new LogInterpolator(); 4053d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette 41ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette private static final float GLOBAL_SPEED = 1.0f; 42b996d809bf10a9ad1f6f6be790d0261fe1565f3bAlan Viverette private static final float WAVE_TOUCH_DOWN_ACCELERATION = 1024.0f * GLOBAL_SPEED; 434b65f0ebee11dd95cd4a03329bfa135ec5582badChristian Robertson private static final float WAVE_TOUCH_UP_ACCELERATION = 3400.0f * GLOBAL_SPEED; 444b65f0ebee11dd95cd4a03329bfa135ec5582badChristian Robertson private static final float WAVE_OPACITY_DECAY_VELOCITY = 3.0f / GLOBAL_SPEED; 4553d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette 464b65f0ebee11dd95cd4a03329bfa135ec5582badChristian Robertson private static final long RIPPLE_ENTER_DELAY = 80; 47b996d809bf10a9ad1f6f6be790d0261fe1565f3bAlan Viverette 48ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette // Hardware animators. 496ce6d70f9c78f0197f1369246bf55a5f6b8d7ba4Alan Viverette private final ArrayList<RenderNodeAnimator> mRunningAnimations = 506ce6d70f9c78f0197f1369246bf55a5f6b8d7ba4Alan Viverette new ArrayList<RenderNodeAnimator>(); 5153d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette 524d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette private final RippleDrawable mOwner; 5353d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette 54ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette /** Bounds used for computing max radius. */ 55223622a50db319d634616311ff74267cf49679e7Alan Viverette private final Rect mBounds; 5647bf0d95ef6c9ac68773567d503749c874a07f2fAlan Viverette 5753d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette /** Maximum ripple radius. */ 5853d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette private float mOuterRadius; 59223622a50db319d634616311ff74267cf49679e7Alan Viverette 604d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette /** Screen density used to adjust pixel-based velocities. */ 614d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette private float mDensity; 624d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette 634d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette private float mStartingX; 644d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette private float mStartingY; 65a4eab42fe437bff3f8ee9dde264579067ea5cdbdAlan Viverette private float mClampedStartingX; 66a4eab42fe437bff3f8ee9dde264579067ea5cdbdAlan Viverette private float mClampedStartingY; 674d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette 68ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette // Hardware rendering properties. 69ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette private CanvasProperty<Paint> mPropPaint; 70ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette private CanvasProperty<Float> mPropRadius; 71ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette private CanvasProperty<Float> mPropX; 72ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette private CanvasProperty<Float> mPropY; 73ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette 74ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette // Software animators. 75ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette private ObjectAnimator mAnimRadius; 76ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette private ObjectAnimator mAnimOpacity; 77ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette private ObjectAnimator mAnimX; 78ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette private ObjectAnimator mAnimY; 79ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette 806ce6d70f9c78f0197f1369246bf55a5f6b8d7ba4Alan Viverette // Temporary paint used for creating canvas properties. 816ce6d70f9c78f0197f1369246bf55a5f6b8d7ba4Alan Viverette private Paint mTempPaint; 826ce6d70f9c78f0197f1369246bf55a5f6b8d7ba4Alan Viverette 83ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette // Software rendering properties. 84ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette private float mOpacity = 1; 85ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette private float mOuterX; 86ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette private float mOuterY; 87223622a50db319d634616311ff74267cf49679e7Alan Viverette 884d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette // Values used to tween between the start and end positions. 89dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette private float mTweenRadius = 0; 90dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette private float mTweenX = 0; 91dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette private float mTweenY = 0; 92c3f35b01b5a21e110ca4eedf09c8c6164ab85dfbAlan Viverette 93ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette /** Whether we should be drawing hardware animations. */ 94ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette private boolean mHardwareAnimating; 95223622a50db319d634616311ff74267cf49679e7Alan Viverette 96ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette /** Whether we can use hardware acceleration for the exit animation. */ 97ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette private boolean mCanUseHardware; 98223622a50db319d634616311ff74267cf49679e7Alan Viverette 99dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette /** Whether we have an explicit maximum radius. */ 100dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette private boolean mHasMaxRadius; 101dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette 102fdbb98e56d4668c7bfa8de59c3c438c0cb69a535Alan Viverette /** Whether we were canceled externally and should avoid self-removal. */ 103fdbb98e56d4668c7bfa8de59c3c438c0cb69a535Alan Viverette private boolean mCanceled; 104fdbb98e56d4668c7bfa8de59c3c438c0cb69a535Alan Viverette 1056dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette private boolean mHasPendingHardwareExit; 1066dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette private int mPendingRadiusDuration; 1076dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette private int mPendingOpacityDuration; 1086dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette 109223622a50db319d634616311ff74267cf49679e7Alan Viverette /** 11053d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette * Creates a new ripple. 111223622a50db319d634616311ff74267cf49679e7Alan Viverette */ 1124d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette public Ripple(RippleDrawable owner, Rect bounds, float startingX, float startingY) { 11353d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette mOwner = owner; 114223622a50db319d634616311ff74267cf49679e7Alan Viverette mBounds = bounds; 115a4eab42fe437bff3f8ee9dde264579067ea5cdbdAlan Viverette 1164d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette mStartingX = startingX; 1174d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette mStartingY = startingY; 1184d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette } 1194d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette 120cc3c573334a9cd2124a8a0ccf2f37884e36f83faAlan Viverette public void setup(int maxRadius, float density) { 1214d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette if (maxRadius != RippleDrawable.RADIUS_AUTO) { 122dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette mHasMaxRadius = true; 1234d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette mOuterRadius = maxRadius; 1244d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette } else { 1254d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette final float halfWidth = mBounds.width() / 2.0f; 1264d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette final float halfHeight = mBounds.height() / 2.0f; 1274d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette mOuterRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight); 1284d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette } 1294d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette 130ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette mOuterX = 0; 131ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette mOuterY = 0; 1324d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette mDensity = density; 133a4eab42fe437bff3f8ee9dde264579067ea5cdbdAlan Viverette 134a4eab42fe437bff3f8ee9dde264579067ea5cdbdAlan Viverette clampStartingPosition(); 135a4eab42fe437bff3f8ee9dde264579067ea5cdbdAlan Viverette } 136a4eab42fe437bff3f8ee9dde264579067ea5cdbdAlan Viverette 1372ae56403542582bd39c0e522bf29844d59300f37Alan Viverette public boolean isHardwareAnimating() { 1382ae56403542582bd39c0e522bf29844d59300f37Alan Viverette return mHardwareAnimating; 1392ae56403542582bd39c0e522bf29844d59300f37Alan Viverette } 1402ae56403542582bd39c0e522bf29844d59300f37Alan Viverette 141a4eab42fe437bff3f8ee9dde264579067ea5cdbdAlan Viverette private void clampStartingPosition() { 142304624100b363137913d1d910690fc83872e41c3Alan Viverette final float cX = mBounds.exactCenterX(); 143304624100b363137913d1d910690fc83872e41c3Alan Viverette final float cY = mBounds.exactCenterY(); 144304624100b363137913d1d910690fc83872e41c3Alan Viverette final float dX = mStartingX - cX; 145304624100b363137913d1d910690fc83872e41c3Alan Viverette final float dY = mStartingY - cY; 146a4eab42fe437bff3f8ee9dde264579067ea5cdbdAlan Viverette final float r = mOuterRadius; 147a4eab42fe437bff3f8ee9dde264579067ea5cdbdAlan Viverette if (dX * dX + dY * dY > r * r) { 148a4eab42fe437bff3f8ee9dde264579067ea5cdbdAlan Viverette // Point is outside the circle, clamp to the circumference. 149a4eab42fe437bff3f8ee9dde264579067ea5cdbdAlan Viverette final double angle = Math.atan2(dY, dX); 150304624100b363137913d1d910690fc83872e41c3Alan Viverette mClampedStartingX = cX + (float) (Math.cos(angle) * r); 151304624100b363137913d1d910690fc83872e41c3Alan Viverette mClampedStartingY = cY + (float) (Math.sin(angle) * r); 152a4eab42fe437bff3f8ee9dde264579067ea5cdbdAlan Viverette } else { 153a4eab42fe437bff3f8ee9dde264579067ea5cdbdAlan Viverette mClampedStartingX = mStartingX; 154a4eab42fe437bff3f8ee9dde264579067ea5cdbdAlan Viverette mClampedStartingY = mStartingY; 155a4eab42fe437bff3f8ee9dde264579067ea5cdbdAlan Viverette } 156ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette } 157ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette 158dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette public void onHotspotBoundsChanged() { 159dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette if (!mHasMaxRadius) { 160dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette final float halfWidth = mBounds.width() / 2.0f; 161dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette final float halfHeight = mBounds.height() / 2.0f; 162dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette mOuterRadius = (float) Math.sqrt(halfWidth * halfWidth + halfHeight * halfHeight); 163a4eab42fe437bff3f8ee9dde264579067ea5cdbdAlan Viverette 164a4eab42fe437bff3f8ee9dde264579067ea5cdbdAlan Viverette clampStartingPosition(); 165dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette } 16653d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette } 16753d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette 168ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette public void setOpacity(float a) { 169ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette mOpacity = a; 17053d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette invalidateSelf(); 17153d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette } 172223622a50db319d634616311ff74267cf49679e7Alan Viverette 173ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette public float getOpacity() { 174ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette return mOpacity; 175ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette } 176ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette 1776ce6d70f9c78f0197f1369246bf55a5f6b8d7ba4Alan Viverette @SuppressWarnings("unused") 178dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette public void setRadiusGravity(float r) { 179dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette mTweenRadius = r; 1804d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette invalidateSelf(); 1814d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette } 1824d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette 1836ce6d70f9c78f0197f1369246bf55a5f6b8d7ba4Alan Viverette @SuppressWarnings("unused") 184dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette public float getRadiusGravity() { 185dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette return mTweenRadius; 1864d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette } 1874d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette 1886ce6d70f9c78f0197f1369246bf55a5f6b8d7ba4Alan Viverette @SuppressWarnings("unused") 189dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette public void setXGravity(float x) { 190dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette mTweenX = x; 19153d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette invalidateSelf(); 19253d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette } 19353d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette 1946ce6d70f9c78f0197f1369246bf55a5f6b8d7ba4Alan Viverette @SuppressWarnings("unused") 195dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette public float getXGravity() { 196dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette return mTweenX; 19747bf0d95ef6c9ac68773567d503749c874a07f2fAlan Viverette } 19853d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette 1996ce6d70f9c78f0197f1369246bf55a5f6b8d7ba4Alan Viverette @SuppressWarnings("unused") 200dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette public void setYGravity(float y) { 201dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette mTweenY = y; 20253d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette invalidateSelf(); 20353d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette } 20453d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette 2056ce6d70f9c78f0197f1369246bf55a5f6b8d7ba4Alan Viverette @SuppressWarnings("unused") 206dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette public float getYGravity() { 207dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette return mTweenY; 20847bf0d95ef6c9ac68773567d503749c874a07f2fAlan Viverette } 209223622a50db319d634616311ff74267cf49679e7Alan Viverette 210223622a50db319d634616311ff74267cf49679e7Alan Viverette /** 211ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette * Draws the ripple centered at (0,0) using the specified paint. 21253d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette */ 213ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette public boolean draw(Canvas c, Paint p) { 214ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette final boolean canUseHardware = c.isHardwareAccelerated(); 215ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette if (mCanUseHardware != canUseHardware && mCanUseHardware) { 216ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette // We've switched from hardware to non-hardware mode. Panic. 217a0c0ca738989fd3ecad8a54a91f0c6a8b30ad1abAlan Viverette cancelHardwareAnimations(true); 218ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette } 219ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette mCanUseHardware = canUseHardware; 22053d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette 221ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette final boolean hasContent; 2226dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette if (canUseHardware && (mHardwareAnimating || mHasPendingHardwareExit)) { 2236dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette hasContent = drawHardware((HardwareCanvas) c, p); 224ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette } else { 225ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette hasContent = drawSoftware(c, p); 226ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette } 227c3f35b01b5a21e110ca4eedf09c8c6164ab85dfbAlan Viverette 228ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette return hasContent; 229ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette } 23053d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette 2316dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette private boolean drawHardware(HardwareCanvas c, Paint p) { 2326dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette if (mHasPendingHardwareExit) { 233d78a44576c6bac5541e04c1f38599d43c9943653Alan Viverette cancelHardwareAnimations(false); 2346dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette startPendingHardwareExit(c, p); 235223622a50db319d634616311ff74267cf49679e7Alan Viverette } 236ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette 237ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette c.drawCircle(mPropX, mPropY, mPropRadius, mPropPaint); 238ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette 239ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette return true; 240223622a50db319d634616311ff74267cf49679e7Alan Viverette } 241223622a50db319d634616311ff74267cf49679e7Alan Viverette 242ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette private boolean drawSoftware(Canvas c, Paint p) { 2434d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette boolean hasContent = false; 24453d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette 245cc3c573334a9cd2124a8a0ccf2f37884e36f83faAlan Viverette final int paintAlpha = p.getAlpha(); 246cc3c573334a9cd2124a8a0ccf2f37884e36f83faAlan Viverette final int alpha = (int) (paintAlpha * mOpacity + 0.5f); 247dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette final float radius = MathUtils.lerp(0, mOuterRadius, mTweenRadius); 248dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette if (alpha > 0 && radius > 0) { 249a4eab42fe437bff3f8ee9dde264579067ea5cdbdAlan Viverette final float x = MathUtils.lerp( 250a4eab42fe437bff3f8ee9dde264579067ea5cdbdAlan Viverette mClampedStartingX - mBounds.exactCenterX(), mOuterX, mTweenX); 251a4eab42fe437bff3f8ee9dde264579067ea5cdbdAlan Viverette final float y = MathUtils.lerp( 252a4eab42fe437bff3f8ee9dde264579067ea5cdbdAlan Viverette mClampedStartingY - mBounds.exactCenterY(), mOuterY, mTweenY); 25353d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette p.setAlpha(alpha); 254dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette c.drawCircle(x, y, radius, p); 255cc3c573334a9cd2124a8a0ccf2f37884e36f83faAlan Viverette p.setAlpha(paintAlpha); 25653d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette hasContent = true; 257223622a50db319d634616311ff74267cf49679e7Alan Viverette } 25812b61f20a4cdab84b28f153e48c4dcbe82ab6f0aAlan Viverette 25953d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette return hasContent; 260223622a50db319d634616311ff74267cf49679e7Alan Viverette } 261d5154ec2bc7e7c0bdfd14fc784912d390afe43ccAlan Viverette 26253d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette /** 263dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette * Returns the maximum bounds of the ripple relative to the ripple center. 26453d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette */ 265d5154ec2bc7e7c0bdfd14fc784912d390afe43ccAlan Viverette public void getBounds(Rect bounds) { 266ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette final int outerX = (int) mOuterX; 267ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette final int outerY = (int) mOuterY; 268036a66596dba32c051a016ca9b5334fbbd39c220Alan Viverette final int r = (int) mOuterRadius + 1; 269ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette bounds.set(outerX - r, outerY - r, outerX + r, outerY + r); 270d5154ec2bc7e7c0bdfd14fc784912d390afe43ccAlan Viverette } 27147bf0d95ef6c9ac68773567d503749c874a07f2fAlan Viverette 27247bf0d95ef6c9ac68773567d503749c874a07f2fAlan Viverette /** 2734d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette * Specifies the starting position relative to the drawable bounds. No-op if 2744d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette * the ripple has already entered. 2754d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette */ 2764d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette public void move(float x, float y) { 2774d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette mStartingX = x; 2784d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette mStartingY = y; 279a4eab42fe437bff3f8ee9dde264579067ea5cdbdAlan Viverette 280a4eab42fe437bff3f8ee9dde264579067ea5cdbdAlan Viverette clampStartingPosition(); 2814d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette } 2824d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette 2834d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette /** 2844d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette * Starts the enter animation. 28553d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette */ 2864d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette public void enter() { 287fdbb98e56d4668c7bfa8de59c3c438c0cb69a535Alan Viverette cancel(); 288fdbb98e56d4668c7bfa8de59c3c438c0cb69a535Alan Viverette 289ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette final int radiusDuration = (int) 2904d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette (1000 * Math.sqrt(mOuterRadius / WAVE_TOUCH_DOWN_ACCELERATION * mDensity) + 0.5); 291ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette 292dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette final ObjectAnimator radius = ObjectAnimator.ofFloat(this, "radiusGravity", 1); 293ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette radius.setAutoCancel(true); 294ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette radius.setDuration(radiusDuration); 2954d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette radius.setInterpolator(LINEAR_INTERPOLATOR); 296b996d809bf10a9ad1f6f6be790d0261fe1565f3bAlan Viverette radius.setStartDelay(RIPPLE_ENTER_DELAY); 297ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette 2984d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette final ObjectAnimator cX = ObjectAnimator.ofFloat(this, "xGravity", 1); 299ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette cX.setAutoCancel(true); 300ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette cX.setDuration(radiusDuration); 301b996d809bf10a9ad1f6f6be790d0261fe1565f3bAlan Viverette cX.setInterpolator(LINEAR_INTERPOLATOR); 302b996d809bf10a9ad1f6f6be790d0261fe1565f3bAlan Viverette cX.setStartDelay(RIPPLE_ENTER_DELAY); 303ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette 3044d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette final ObjectAnimator cY = ObjectAnimator.ofFloat(this, "yGravity", 1); 305ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette cY.setAutoCancel(true); 306ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette cY.setDuration(radiusDuration); 307b996d809bf10a9ad1f6f6be790d0261fe1565f3bAlan Viverette cY.setInterpolator(LINEAR_INTERPOLATOR); 308b996d809bf10a9ad1f6f6be790d0261fe1565f3bAlan Viverette cY.setStartDelay(RIPPLE_ENTER_DELAY); 309ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette 310ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette mAnimRadius = radius; 311ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette mAnimX = cX; 312ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette mAnimY = cY; 313ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette 314ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette // Enter animations always run on the UI thread, since it's unlikely 315ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette // that anything interesting is happening until the user lifts their 316ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette // finger. 317ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette radius.start(); 318ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette cX.start(); 319ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette cY.start(); 32053d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette } 32153d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette 32253d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette /** 323ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette * Starts the exit animation. 32453d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette */ 32553d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette public void exit() { 326dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette final float radius = MathUtils.lerp(0, mOuterRadius, mTweenRadius); 327ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette final float remaining; 328ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette if (mAnimRadius != null && mAnimRadius.isRunning()) { 329dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette remaining = mOuterRadius - radius; 330ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette } else { 331ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette remaining = mOuterRadius; 33253d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette } 33353d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette 3346dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette cancel(); 3356dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette 336ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette final int radiusDuration = (int) (1000 * Math.sqrt(remaining / (WAVE_TOUCH_UP_ACCELERATION 3374d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette + WAVE_TOUCH_DOWN_ACCELERATION) * mDensity) + 0.5); 338ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette final int opacityDuration = (int) (1000 * mOpacity / WAVE_OPACITY_DECAY_VELOCITY + 0.5f); 33953d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette 340ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette if (mCanUseHardware) { 3416dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette createPendingHardwareExit(radiusDuration, opacityDuration); 342ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette } else { 3436ce6d70f9c78f0197f1369246bf55a5f6b8d7ba4Alan Viverette exitSoftware(radiusDuration, opacityDuration); 344ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette } 345de399397947c5379c61a1003c017b96accbbf545Alan Viverette } 346de399397947c5379c61a1003c017b96accbbf545Alan Viverette 3476dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette private void createPendingHardwareExit(int radiusDuration, int opacityDuration) { 3486dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette mHasPendingHardwareExit = true; 3496dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette mPendingRadiusDuration = radiusDuration; 3506dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette mPendingOpacityDuration = opacityDuration; 3516dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette 3526dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette // The animation will start on the next draw(). 3536dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette invalidateSelf(); 3546dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette } 3556dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette 3566dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette private void startPendingHardwareExit(HardwareCanvas c, Paint p) { 3576dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette mHasPendingHardwareExit = false; 3586dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette 3596dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette final int radiusDuration = mPendingRadiusDuration; 3606dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette final int opacityDuration = mPendingOpacityDuration; 361ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette 362a4eab42fe437bff3f8ee9dde264579067ea5cdbdAlan Viverette final float startX = MathUtils.lerp( 363a4eab42fe437bff3f8ee9dde264579067ea5cdbdAlan Viverette mClampedStartingX - mBounds.exactCenterX(), mOuterX, mTweenX); 364a4eab42fe437bff3f8ee9dde264579067ea5cdbdAlan Viverette final float startY = MathUtils.lerp( 365a4eab42fe437bff3f8ee9dde264579067ea5cdbdAlan Viverette mClampedStartingY - mBounds.exactCenterY(), mOuterY, mTweenY); 366ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette 367dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette final float startRadius = MathUtils.lerp(0, mOuterRadius, mTweenRadius); 3686dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette final Paint paint = getTempPaint(p); 3696dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette paint.setAlpha((int) (paint.getAlpha() * mOpacity + 0.5f)); 370ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette mPropPaint = CanvasProperty.createPaint(paint); 371dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette mPropRadius = CanvasProperty.createFloat(startRadius); 372dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette mPropX = CanvasProperty.createFloat(startX); 373dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette mPropY = CanvasProperty.createFloat(startY); 374ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette 375dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette final RenderNodeAnimator radiusAnim = new RenderNodeAnimator(mPropRadius, mOuterRadius); 376dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette radiusAnim.setDuration(radiusDuration); 377b996d809bf10a9ad1f6f6be790d0261fe1565f3bAlan Viverette radiusAnim.setInterpolator(DECEL_INTERPOLATOR); 3786dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette radiusAnim.setTarget(c); 3796dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette radiusAnim.start(); 380ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette 381dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette final RenderNodeAnimator xAnim = new RenderNodeAnimator(mPropX, mOuterX); 382dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette xAnim.setDuration(radiusDuration); 383b996d809bf10a9ad1f6f6be790d0261fe1565f3bAlan Viverette xAnim.setInterpolator(DECEL_INTERPOLATOR); 3846dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette xAnim.setTarget(c); 3856dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette xAnim.start(); 386ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette 387dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette final RenderNodeAnimator yAnim = new RenderNodeAnimator(mPropY, mOuterY); 388dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette yAnim.setDuration(radiusDuration); 389b996d809bf10a9ad1f6f6be790d0261fe1565f3bAlan Viverette yAnim.setInterpolator(DECEL_INTERPOLATOR); 3906dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette yAnim.setTarget(c); 3916dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette yAnim.start(); 392ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette 393dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette final RenderNodeAnimator opacityAnim = new RenderNodeAnimator(mPropPaint, 394ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette RenderNodeAnimator.PAINT_ALPHA, 0); 395dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette opacityAnim.setDuration(opacityDuration); 396dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette opacityAnim.setInterpolator(LINEAR_INTERPOLATOR); 3976ce6d70f9c78f0197f1369246bf55a5f6b8d7ba4Alan Viverette opacityAnim.addListener(mAnimationListener); 3986dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette opacityAnim.setTarget(c); 3996dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette opacityAnim.start(); 400de399397947c5379c61a1003c017b96accbbf545Alan Viverette 4016dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette mRunningAnimations.add(radiusAnim); 4026dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette mRunningAnimations.add(opacityAnim); 4036dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette mRunningAnimations.add(xAnim); 4046dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette mRunningAnimations.add(yAnim); 405de399397947c5379c61a1003c017b96accbbf545Alan Viverette 406ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette mHardwareAnimating = true; 40753d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette 408a3f0c2b21a73a82a919abe247c4046d114f3712cAlan Viverette // Set up the software values to match the hardware end values. 409a3f0c2b21a73a82a919abe247c4046d114f3712cAlan Viverette mOpacity = 0; 410a3f0c2b21a73a82a919abe247c4046d114f3712cAlan Viverette mTweenX = 1; 411a3f0c2b21a73a82a919abe247c4046d114f3712cAlan Viverette mTweenY = 1; 412a3f0c2b21a73a82a919abe247c4046d114f3712cAlan Viverette mTweenRadius = 1; 41353d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette } 41453d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette 415fdbb98e56d4668c7bfa8de59c3c438c0cb69a535Alan Viverette /** 416fdbb98e56d4668c7bfa8de59c3c438c0cb69a535Alan Viverette * Jump all animations to their end state. The caller is responsible for 417fdbb98e56d4668c7bfa8de59c3c438c0cb69a535Alan Viverette * removing the ripple from the list of animating ripples. 418fdbb98e56d4668c7bfa8de59c3c438c0cb69a535Alan Viverette */ 419d78a44576c6bac5541e04c1f38599d43c9943653Alan Viverette public void jump() { 420fdbb98e56d4668c7bfa8de59c3c438c0cb69a535Alan Viverette mCanceled = true; 421d78a44576c6bac5541e04c1f38599d43c9943653Alan Viverette endSoftwareAnimations(); 422a3f0c2b21a73a82a919abe247c4046d114f3712cAlan Viverette cancelHardwareAnimations(true); 423fdbb98e56d4668c7bfa8de59c3c438c0cb69a535Alan Viverette mCanceled = false; 424d78a44576c6bac5541e04c1f38599d43c9943653Alan Viverette } 425d78a44576c6bac5541e04c1f38599d43c9943653Alan Viverette 426d78a44576c6bac5541e04c1f38599d43c9943653Alan Viverette private void endSoftwareAnimations() { 427d78a44576c6bac5541e04c1f38599d43c9943653Alan Viverette if (mAnimRadius != null) { 428d78a44576c6bac5541e04c1f38599d43c9943653Alan Viverette mAnimRadius.end(); 429a2362c9251af9d27506aa12f49da42e019665555Alan Viverette mAnimRadius = null; 430d78a44576c6bac5541e04c1f38599d43c9943653Alan Viverette } 431d78a44576c6bac5541e04c1f38599d43c9943653Alan Viverette 432d78a44576c6bac5541e04c1f38599d43c9943653Alan Viverette if (mAnimOpacity != null) { 433d78a44576c6bac5541e04c1f38599d43c9943653Alan Viverette mAnimOpacity.end(); 434a2362c9251af9d27506aa12f49da42e019665555Alan Viverette mAnimOpacity = null; 435d78a44576c6bac5541e04c1f38599d43c9943653Alan Viverette } 436d78a44576c6bac5541e04c1f38599d43c9943653Alan Viverette 437d78a44576c6bac5541e04c1f38599d43c9943653Alan Viverette if (mAnimX != null) { 438d78a44576c6bac5541e04c1f38599d43c9943653Alan Viverette mAnimX.end(); 439a2362c9251af9d27506aa12f49da42e019665555Alan Viverette mAnimX = null; 440d78a44576c6bac5541e04c1f38599d43c9943653Alan Viverette } 441d78a44576c6bac5541e04c1f38599d43c9943653Alan Viverette 442d78a44576c6bac5541e04c1f38599d43c9943653Alan Viverette if (mAnimY != null) { 443d78a44576c6bac5541e04c1f38599d43c9943653Alan Viverette mAnimY.end(); 444a2362c9251af9d27506aa12f49da42e019665555Alan Viverette mAnimY = null; 445d78a44576c6bac5541e04c1f38599d43c9943653Alan Viverette } 446d78a44576c6bac5541e04c1f38599d43c9943653Alan Viverette } 447d78a44576c6bac5541e04c1f38599d43c9943653Alan Viverette 4486dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette private Paint getTempPaint(Paint original) { 4496ce6d70f9c78f0197f1369246bf55a5f6b8d7ba4Alan Viverette if (mTempPaint == null) { 4506ce6d70f9c78f0197f1369246bf55a5f6b8d7ba4Alan Viverette mTempPaint = new Paint(); 4516ce6d70f9c78f0197f1369246bf55a5f6b8d7ba4Alan Viverette } 4526dfa60f33ca6018959ebff1efde82db7d2aed1e3Alan Viverette mTempPaint.set(original); 4536ce6d70f9c78f0197f1369246bf55a5f6b8d7ba4Alan Viverette return mTempPaint; 4546ce6d70f9c78f0197f1369246bf55a5f6b8d7ba4Alan Viverette } 4556ce6d70f9c78f0197f1369246bf55a5f6b8d7ba4Alan Viverette 4566ce6d70f9c78f0197f1369246bf55a5f6b8d7ba4Alan Viverette private void exitSoftware(int radiusDuration, int opacityDuration) { 457dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette final ObjectAnimator radiusAnim = ObjectAnimator.ofFloat(this, "radiusGravity", 1); 458dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette radiusAnim.setAutoCancel(true); 459dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette radiusAnim.setDuration(radiusDuration); 460b996d809bf10a9ad1f6f6be790d0261fe1565f3bAlan Viverette radiusAnim.setInterpolator(DECEL_INTERPOLATOR); 461dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette 462dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette final ObjectAnimator xAnim = ObjectAnimator.ofFloat(this, "xGravity", 1); 463dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette xAnim.setAutoCancel(true); 464dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette xAnim.setDuration(radiusDuration); 465b996d809bf10a9ad1f6f6be790d0261fe1565f3bAlan Viverette xAnim.setInterpolator(DECEL_INTERPOLATOR); 466dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette 467dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette final ObjectAnimator yAnim = ObjectAnimator.ofFloat(this, "yGravity", 1); 468dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette yAnim.setAutoCancel(true); 469dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette yAnim.setDuration(radiusDuration); 470b996d809bf10a9ad1f6f6be790d0261fe1565f3bAlan Viverette yAnim.setInterpolator(DECEL_INTERPOLATOR); 471dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette 472dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette final ObjectAnimator opacityAnim = ObjectAnimator.ofFloat(this, "opacity", 0); 473dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette opacityAnim.setAutoCancel(true); 474dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette opacityAnim.setDuration(opacityDuration); 475dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette opacityAnim.setInterpolator(LINEAR_INTERPOLATOR); 4766ce6d70f9c78f0197f1369246bf55a5f6b8d7ba4Alan Viverette opacityAnim.addListener(mAnimationListener); 47753d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette 478dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette mAnimRadius = radiusAnim; 479dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette mAnimOpacity = opacityAnim; 4806ce6d70f9c78f0197f1369246bf55a5f6b8d7ba4Alan Viverette mAnimX = xAnim; 4816ce6d70f9c78f0197f1369246bf55a5f6b8d7ba4Alan Viverette mAnimY = yAnim; 482dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette 483dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette radiusAnim.start(); 484dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette opacityAnim.start(); 485dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette xAnim.start(); 486dc6046fca37264b48e9c959f38d08cfb78f436edAlan Viverette yAnim.start(); 48753d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette } 48853d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette 48953d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette /** 490fdbb98e56d4668c7bfa8de59c3c438c0cb69a535Alan Viverette * Cancels all animations. The caller is responsible for removing 491fdbb98e56d4668c7bfa8de59c3c438c0cb69a535Alan Viverette * the ripple from the list of animating ripples. 49253d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette */ 493ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette public void cancel() { 494fdbb98e56d4668c7bfa8de59c3c438c0cb69a535Alan Viverette mCanceled = true; 495ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette cancelSoftwareAnimations(); 4969bc11ac168d63900589158074028e6c480579421Alan Viverette cancelHardwareAnimations(false); 497fdbb98e56d4668c7bfa8de59c3c438c0cb69a535Alan Viverette mCanceled = false; 498ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette } 499de399397947c5379c61a1003c017b96accbbf545Alan Viverette 500ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette private void cancelSoftwareAnimations() { 501ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette if (mAnimRadius != null) { 502ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette mAnimRadius.cancel(); 503a2362c9251af9d27506aa12f49da42e019665555Alan Viverette mAnimRadius = null; 504ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette } 505de399397947c5379c61a1003c017b96accbbf545Alan Viverette 506ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette if (mAnimOpacity != null) { 507ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette mAnimOpacity.cancel(); 508a2362c9251af9d27506aa12f49da42e019665555Alan Viverette mAnimOpacity = null; 509ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette } 510ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette 511ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette if (mAnimX != null) { 512ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette mAnimX.cancel(); 513a2362c9251af9d27506aa12f49da42e019665555Alan Viverette mAnimX = null; 514ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette } 515ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette 516ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette if (mAnimY != null) { 517ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette mAnimY.cancel(); 518a2362c9251af9d27506aa12f49da42e019665555Alan Viverette mAnimY = null; 519ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette } 52053d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette } 52153d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette 52253d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette /** 523ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette * Cancels any running hardware animations. 52447bf0d95ef6c9ac68773567d503749c874a07f2fAlan Viverette */ 5259bc11ac168d63900589158074028e6c480579421Alan Viverette private void cancelHardwareAnimations(boolean jumpToEnd) { 526ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette final ArrayList<RenderNodeAnimator> runningAnimations = mRunningAnimations; 5276ce6d70f9c78f0197f1369246bf55a5f6b8d7ba4Alan Viverette final int N = runningAnimations.size(); 528ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette for (int i = 0; i < N; i++) { 5299bc11ac168d63900589158074028e6c480579421Alan Viverette if (jumpToEnd) { 5309bc11ac168d63900589158074028e6c480579421Alan Viverette runningAnimations.get(i).end(); 5319bc11ac168d63900589158074028e6c480579421Alan Viverette } else { 5329bc11ac168d63900589158074028e6c480579421Alan Viverette runningAnimations.get(i).cancel(); 5339bc11ac168d63900589158074028e6c480579421Alan Viverette } 53447bf0d95ef6c9ac68773567d503749c874a07f2fAlan Viverette } 535ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette runningAnimations.clear(); 536d78a44576c6bac5541e04c1f38599d43c9943653Alan Viverette 5379bc11ac168d63900589158074028e6c480579421Alan Viverette if (mHasPendingHardwareExit) { 5389bc11ac168d63900589158074028e6c480579421Alan Viverette // If we had a pending hardware exit, jump to the end state. 5399bc11ac168d63900589158074028e6c480579421Alan Viverette mHasPendingHardwareExit = false; 5409bc11ac168d63900589158074028e6c480579421Alan Viverette 5419bc11ac168d63900589158074028e6c480579421Alan Viverette if (jumpToEnd) { 5429bc11ac168d63900589158074028e6c480579421Alan Viverette mOpacity = 0; 5439bc11ac168d63900589158074028e6c480579421Alan Viverette mTweenX = 1; 5449bc11ac168d63900589158074028e6c480579421Alan Viverette mTweenY = 1; 5459bc11ac168d63900589158074028e6c480579421Alan Viverette mTweenRadius = 1; 5469bc11ac168d63900589158074028e6c480579421Alan Viverette } 5479bc11ac168d63900589158074028e6c480579421Alan Viverette } 5489bc11ac168d63900589158074028e6c480579421Alan Viverette 549fdbb98e56d4668c7bfa8de59c3c438c0cb69a535Alan Viverette mHardwareAnimating = false; 550ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette } 551ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette 5524d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette private void removeSelf() { 5534d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette // The owner will invalidate itself. 554fdbb98e56d4668c7bfa8de59c3c438c0cb69a535Alan Viverette if (!mCanceled) { 555fdbb98e56d4668c7bfa8de59c3c438c0cb69a535Alan Viverette mOwner.removeRipple(this); 556fdbb98e56d4668c7bfa8de59c3c438c0cb69a535Alan Viverette } 5574d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette } 5584d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette 559ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette private void invalidateSelf() { 560ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette mOwner.invalidateSelf(); 56147bf0d95ef6c9ac68773567d503749c874a07f2fAlan Viverette } 56247bf0d95ef6c9ac68773567d503749c874a07f2fAlan Viverette 563ad2f8e334f3ef22d3e412b0660a2e1f996f94116Alan Viverette private final AnimatorListenerAdapter mAnimationListener = new AnimatorListenerAdapter() { 56453d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette @Override 56553d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette public void onAnimationEnd(Animator animation) { 5664d2f2483f6d9e2eb25d843d676981f4ebc9c79e5Alan Viverette removeSelf(); 56747bf0d95ef6c9ac68773567d503749c874a07f2fAlan Viverette } 56853d1cfe2d073bff7c7771d5f7dd9108062ddc706Alan Viverette }; 5694b65f0ebee11dd95cd4a03329bfa135ec5582badChristian Robertson 5704b65f0ebee11dd95cd4a03329bfa135ec5582badChristian Robertson /** 5714b65f0ebee11dd95cd4a03329bfa135ec5582badChristian Robertson * Interpolator with a smooth log deceleration 5724b65f0ebee11dd95cd4a03329bfa135ec5582badChristian Robertson */ 5734b65f0ebee11dd95cd4a03329bfa135ec5582badChristian Robertson private static final class LogInterpolator implements TimeInterpolator { 5744b65f0ebee11dd95cd4a03329bfa135ec5582badChristian Robertson @Override 5754b65f0ebee11dd95cd4a03329bfa135ec5582badChristian Robertson public float getInterpolation(float input) { 5764b65f0ebee11dd95cd4a03329bfa135ec5582badChristian Robertson return 1 - (float) Math.pow(400, -input * 1.4); 5774b65f0ebee11dd95cd4a03329bfa135ec5582badChristian Robertson } 5784b65f0ebee11dd95cd4a03329bfa135ec5582badChristian Robertson } 579223622a50db319d634616311ff74267cf49679e7Alan Viverette} 580