RippleBackground.java revision f6829a0a618b4523619ec53c996b04d67e3186b9
1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.graphics.drawable; 18 19import android.animation.Animator; 20import android.animation.AnimatorSet; 21import android.animation.ObjectAnimator; 22import android.animation.TimeInterpolator; 23import android.graphics.Canvas; 24import android.graphics.CanvasProperty; 25import android.graphics.Paint; 26import android.graphics.Rect; 27import android.util.FloatProperty; 28import android.view.DisplayListCanvas; 29import android.view.RenderNodeAnimator; 30import android.view.animation.LinearInterpolator; 31 32/** 33 * Draws a ripple background. 34 */ 35class RippleBackground extends RippleComponent { 36 private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator(); 37 38 private static final int OPACITY_ENTER_DURATION = 600; 39 private static final int OPACITY_ENTER_DURATION_FAST = 120; 40 private static final int OPACITY_EXIT_DURATION = 480; 41 42 // Hardware rendering properties. 43 private CanvasProperty<Paint> mPropPaint; 44 private CanvasProperty<Float> mPropRadius; 45 private CanvasProperty<Float> mPropX; 46 private CanvasProperty<Float> mPropY; 47 48 // Software rendering properties. 49 private float mOpacity = 0; 50 51 public RippleBackground(RippleDrawable owner, Rect bounds) { 52 super(owner, bounds); 53 } 54 55 public boolean isVisible() { 56 return mOpacity > 0 || isHardwareAnimating(); 57 } 58 59 @Override 60 protected boolean drawSoftware(Canvas c, Paint p) { 61 boolean hasContent = false; 62 63 final int origAlpha = p.getAlpha(); 64 final int alpha = (int) (origAlpha * mOpacity + 0.5f); 65 if (alpha > 0) { 66 p.setAlpha(alpha); 67 c.drawCircle(0, 0, mTargetRadius, p); 68 p.setAlpha(origAlpha); 69 hasContent = true; 70 } 71 72 return hasContent; 73 } 74 75 @Override 76 protected boolean drawHardware(DisplayListCanvas c) { 77 c.drawCircle(mPropX, mPropY, mPropRadius, mPropPaint); 78 return true; 79 } 80 81 @Override 82 protected Animator createSoftwareEnter(boolean fast) { 83 // Linear enter based on current opacity. 84 final int maxDuration = fast ? OPACITY_ENTER_DURATION_FAST : OPACITY_ENTER_DURATION; 85 final int duration = (int) ((1 - mOpacity) * maxDuration); 86 87 final ObjectAnimator opacity = ObjectAnimator.ofFloat(this, OPACITY, 1); 88 opacity.setAutoCancel(true); 89 opacity.setDuration(duration); 90 opacity.setInterpolator(LINEAR_INTERPOLATOR); 91 92 return opacity; 93 } 94 95 @Override 96 protected Animator createSoftwareExit() { 97 final AnimatorSet set = new AnimatorSet(); 98 99 // Linear exit after enter is completed. 100 final ObjectAnimator exit = ObjectAnimator.ofFloat(this, RippleBackground.OPACITY, 0); 101 exit.setInterpolator(LINEAR_INTERPOLATOR); 102 exit.setDuration(OPACITY_EXIT_DURATION); 103 exit.setAutoCancel(true); 104 105 final AnimatorSet.Builder builder = set.play(exit); 106 107 // Linear "fast" enter based on current opacity. 108 final int fastEnterDuration = (int) ((1 - mOpacity) * OPACITY_ENTER_DURATION_FAST); 109 if (fastEnterDuration > 0) { 110 final ObjectAnimator enter = ObjectAnimator.ofFloat(this, RippleBackground.OPACITY, 1); 111 enter.setInterpolator(LINEAR_INTERPOLATOR); 112 enter.setDuration(fastEnterDuration); 113 enter.setAutoCancel(true); 114 115 builder.after(enter); 116 } 117 118 return set; 119 } 120 121 @Override 122 protected RenderNodeAnimatorSet createHardwareExit(Paint p) { 123 final RenderNodeAnimatorSet set = new RenderNodeAnimatorSet(); 124 125 final int targetAlpha = p.getAlpha(); 126 final int currentAlpha = (int) (mOpacity * targetAlpha + 0.5f); 127 p.setAlpha(currentAlpha); 128 129 mPropPaint = CanvasProperty.createPaint(p); 130 mPropRadius = CanvasProperty.createFloat(mTargetRadius); 131 mPropX = CanvasProperty.createFloat(0); 132 mPropY = CanvasProperty.createFloat(0); 133 134 // Linear "fast" enter based on current opacity. 135 final int fastEnterDuration = (int) ((1 - mOpacity) * OPACITY_ENTER_DURATION_FAST); 136 if (fastEnterDuration > 0) { 137 final RenderNodeAnimator enter = new RenderNodeAnimator( 138 mPropPaint, RenderNodeAnimator.PAINT_ALPHA, targetAlpha); 139 enter.setInterpolator(LINEAR_INTERPOLATOR); 140 enter.setDuration(fastEnterDuration); 141 set.add(enter); 142 } 143 144 // Linear exit after enter is completed. 145 final RenderNodeAnimator exit = new RenderNodeAnimator( 146 mPropPaint, RenderNodeAnimator.PAINT_ALPHA, 0); 147 exit.setInterpolator(LINEAR_INTERPOLATOR); 148 exit.setDuration(OPACITY_EXIT_DURATION); 149 exit.setStartDelay(fastEnterDuration); 150 set.add(exit); 151 152 return set; 153 } 154 155 @Override 156 protected void jumpValuesToExit() { 157 mOpacity = 0; 158 } 159 160 private static abstract class BackgroundProperty extends FloatProperty<RippleBackground> { 161 public BackgroundProperty(String name) { 162 super(name); 163 } 164 } 165 166 private static final BackgroundProperty OPACITY = new BackgroundProperty("opacity") { 167 @Override 168 public void setValue(RippleBackground object, float value) { 169 object.mOpacity = value; 170 object.invalidateSelf(); 171 } 172 173 @Override 174 public Float get(RippleBackground object) { 175 return object.mOpacity; 176 } 177 }; 178} 179