1 /* 2 * Copyright (C) 2012 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 17 package com.android.incallui.widget.multiwaveview; 18 19 import android.graphics.Canvas; 20 import android.graphics.Color; 21 import android.graphics.Paint; 22 import android.graphics.drawable.Drawable; 23 import android.util.Log; 24 25 import java.util.ArrayList; 26 27 public class PointCloud { 28 private static final float MIN_POINT_SIZE = 2.0f; 29 private static final float MAX_POINT_SIZE = 4.0f; 30 private static final int INNER_POINTS = 8; 31 private static final String TAG = "PointCloud"; 32 private ArrayList<Point> mPointCloud = new ArrayList<Point>(); 33 private Drawable mDrawable; 34 private float mCenterX; 35 private float mCenterY; 36 private Paint mPaint; 37 private float mScale = 1.0f; 38 private static final float PI = (float) Math.PI; 39 40 // These allow us to have multiple concurrent animations. 41 WaveManager waveManager = new WaveManager(); 42 GlowManager glowManager = new GlowManager(); 43 private float mOuterRadius; 44 45 public class WaveManager { 46 private float radius = 50; 47 private float width = 200.0f; // TODO: Make configurable 48 private float alpha = 0.0f; 49 public void setRadius(float r) { 50 radius = r; 51 } 52 53 public float getRadius() { 54 return radius; 55 } 56 57 public void setAlpha(float a) { 58 alpha = a; 59 } 60 61 public float getAlpha() { 62 return alpha; 63 } 64 }; 65 66 public class GlowManager { 67 private float x; 68 private float y; 69 private float radius = 0.0f; 70 private float alpha = 0.0f; 71 72 public void setX(float x1) { 73 x = x1; 74 } 75 76 public float getX() { 77 return x; 78 } 79 80 public void setY(float y1) { 81 y = y1; 82 } 83 84 public float getY() { 85 return y; 86 } 87 88 public void setAlpha(float a) { 89 alpha = a; 90 } 91 92 public float getAlpha() { 93 return alpha; 94 } 95 96 public void setRadius(float r) { 97 radius = r; 98 } 99 100 public float getRadius() { 101 return radius; 102 } 103 } 104 105 class Point { 106 float x; 107 float y; 108 float radius; 109 110 public Point(float x2, float y2, float r) { 111 x = (float) x2; 112 y = (float) y2; 113 radius = r; 114 } 115 } 116 117 public PointCloud(Drawable drawable) { 118 mPaint = new Paint(); 119 mPaint.setFilterBitmap(true); 120 mPaint.setColor(Color.rgb(255, 255, 255)); // TODO: make configurable 121 mPaint.setAntiAlias(true); 122 mPaint.setDither(true); 123 124 mDrawable = drawable; 125 if (mDrawable != null) { 126 drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); 127 } 128 } 129 130 public void setCenter(float x, float y) { 131 mCenterX = x; 132 mCenterY = y; 133 } 134 135 public void makePointCloud(float innerRadius, float outerRadius) { 136 if (innerRadius == 0) { 137 Log.w(TAG, "Must specify an inner radius"); 138 return; 139 } 140 mOuterRadius = outerRadius; 141 mPointCloud.clear(); 142 final float pointAreaRadius = (outerRadius - innerRadius); 143 final float ds = (2.0f * PI * innerRadius / INNER_POINTS); 144 final int bands = (int) Math.round(pointAreaRadius / ds); 145 final float dr = pointAreaRadius / bands; 146 float r = innerRadius; 147 for (int b = 0; b <= bands; b++, r += dr) { 148 float circumference = 2.0f * PI * r; 149 final int pointsInBand = (int) (circumference / ds); 150 float eta = PI/2.0f; 151 float dEta = 2.0f * PI / pointsInBand; 152 for (int i = 0; i < pointsInBand; i++) { 153 float x = r * (float) Math.cos(eta); 154 float y = r * (float) Math.sin(eta); 155 eta += dEta; 156 mPointCloud.add(new Point(x, y, r)); 157 } 158 } 159 } 160 161 public void setScale(float scale) { 162 mScale = scale; 163 } 164 165 public float getScale() { 166 return mScale; 167 } 168 169 private static float hypot(float x, float y) { 170 return (float) Math.hypot(x, y); 171 } 172 173 private static float max(float a, float b) { 174 return a > b ? a : b; 175 } 176 177 public int getAlphaForPoint(Point point) { 178 // Contribution from positional glow 179 float glowDistance = hypot(glowManager.x - point.x, glowManager.y - point.y); 180 float glowAlpha = 0.0f; 181 182 if (glowDistance < glowManager.radius) { 183 double cos = Math.cos(Math.PI * 0.25d * glowDistance / glowManager.radius); 184 glowAlpha = glowManager.alpha * max(0.0f, (float) Math.pow(cos, 10.0d)); 185 } 186 187 // Compute contribution from Wave 188 float radius = hypot(point.x, point.y); 189 float distanceToWaveRing = (radius - waveManager.radius); 190 float waveAlpha = 0.0f; 191 if (distanceToWaveRing < waveManager.width * 0.5f && distanceToWaveRing < 0.0f) { 192 double cos = Math.cos(Math.PI * 0.25d * distanceToWaveRing / waveManager.width); 193 waveAlpha = waveManager.alpha * max(0.0f, (float) Math.pow(cos, 20.0d)); 194 } 195 196 return (int) (max(glowAlpha, waveAlpha) * 255); 197 } 198 199 private float interp(float min, float max, float f) { 200 return min + (max - min) * f; 201 } 202 203 public void draw(Canvas canvas) { 204 ArrayList<Point> points = mPointCloud; 205 canvas.save(Canvas.MATRIX_SAVE_FLAG); 206 canvas.scale(mScale, mScale, mCenterX, mCenterY); 207 for (int i = 0; i < points.size(); i++) { 208 Point point = points.get(i); 209 final float pointSize = interp(MAX_POINT_SIZE, MIN_POINT_SIZE, 210 point.radius / mOuterRadius); 211 final float px = point.x + mCenterX; 212 final float py = point.y + mCenterY; 213 int alpha = getAlphaForPoint(point); 214 215 if (alpha == 0) continue; 216 217 if (mDrawable != null) { 218 canvas.save(Canvas.MATRIX_SAVE_FLAG); 219 final float cx = mDrawable.getIntrinsicWidth() * 0.5f; 220 final float cy = mDrawable.getIntrinsicHeight() * 0.5f; 221 final float s = pointSize / MAX_POINT_SIZE; 222 canvas.scale(s, s, px, py); 223 canvas.translate(px - cx, py - cy); 224 mDrawable.setAlpha(alpha); 225 mDrawable.draw(canvas); 226 canvas.restore(); 227 } else { 228 mPaint.setAlpha(alpha); 229 canvas.drawCircle(px, py, pointSize, mPaint); 230 } 231 } 232 canvas.restore(); 233 } 234 235 } 236