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