1bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen/*
2bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen * Copyright (C) 2009 The Android Open Source Project
3bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen *
4bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen * Licensed under the Apache License, Version 2.0 (the "License");
5bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen * you may not use this file except in compliance with the License.
6bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen * You may obtain a copy of the License at
7bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen *
8bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen *      http://www.apache.org/licenses/LICENSE-2.0
9bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen *
10bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen * Unless required by applicable law or agreed to in writing, software
11bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen * distributed under the License is distributed on an "AS IS" BASIS,
12bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen * See the License for the specific language governing permissions and
14bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen * limitations under the License.
15bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen */
16bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen
17bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissenpackage com.android.musicvis.vis1;
18bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen
19f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurentimport com.android.musicvis.AudioCapture;
20f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent
21bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissenimport android.graphics.Canvas;
22bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissenimport android.graphics.Paint;
23bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissenimport android.graphics.Rect;
24bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissenimport android.media.MediaPlayer;
25bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissenimport android.os.Handler;
26bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissenimport android.os.SystemClock;
27bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissenimport android.service.wallpaper.WallpaperService;
28bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissenimport android.util.Log;
29bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissenimport android.view.MotionEvent;
30bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissenimport android.view.SurfaceHolder;
31bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen
32f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurentimport java.util.Arrays;
33f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent
34bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissenpublic class Visualization1 extends WallpaperService {
35bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen
36bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen    private final Handler mHandler = new Handler();
37bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen
38bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen    @Override
39bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen    public void onCreate() {
40bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        super.onCreate();
41bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen    }
42bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen
43bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen    @Override
44bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen    public void onDestroy() {
45bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        super.onDestroy();
46bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen    }
47bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen
48bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen    @Override
49bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen    public Engine onCreateEngine() {
50bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        return new CubeEngine();
51bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen    }
52bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen
53bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen    class CubeEngine extends Engine {
54bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen
55bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        private final Paint mPaint = new Paint();
56bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        private float mOffset;
57bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        private float mTouchX = -1;
58bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        private float mTouchY = -1;
59bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        private long mStartTime;
60bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        private int mWidth;
61bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        private float mCenterX;
62bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        private float mCenterY;
63f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        private AudioCapture mAudioCapture;
64f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent        private int [] mVizData = new int[1024];
65bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen
66bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        private final Runnable mDrawCube = new Runnable() {
67bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            public void run() {
68bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen                drawFrame();
69bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            }
70bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        };
71bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        private boolean mVisible;
72bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen
73bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        CubeEngine() {
74bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        }
75bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen
76bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        @Override
77bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        public void onCreate(SurfaceHolder surfaceHolder) {
78bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            super.onCreate(surfaceHolder);
79bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen
80bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            final Paint paint = mPaint;
81bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            paint.setColor(0xffffffff);
82bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            paint.setAntiAlias(true);
83bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            paint.setStrokeWidth(2);
84bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            paint.setStrokeCap(Paint.Cap.ROUND);
85bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            paint.setStyle(Paint.Style.STROKE);
86bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen
87bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            mStartTime = SystemClock.elapsedRealtime();
88bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        }
89bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen
90bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        @Override
91bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        public void onDestroy() {
92bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            super.onDestroy();
93bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            mHandler.removeCallbacks(mDrawCube);
94f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent            if (mAudioCapture != null) {
95f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                mAudioCapture.stop();
96f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                mAudioCapture.release();
97f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                mAudioCapture = null;
98f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent            }
99bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        }
100bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen
101bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        @Override
102bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        public void onVisibilityChanged(boolean visible) {
103bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            mVisible = visible;
104bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            if (visible) {
105f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                if (mAudioCapture == null) {
106f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                    mAudioCapture = new AudioCapture(AudioCapture.TYPE_PCM, 1024);
107f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                }
108f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                mAudioCapture.start();
109bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen                drawFrame();
110bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            } else {
111bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen                mHandler.removeCallbacks(mDrawCube);
112f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                if (mAudioCapture != null) {
113f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                    mAudioCapture.stop();
114f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                    mAudioCapture.release();
115f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                    mAudioCapture = null;
116f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                }
117bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            }
118bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        }
119bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen
120bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        @Override
121bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
122bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            super.onSurfaceChanged(holder, format, width, height);
123bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            mWidth = width;
124bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            mCenterX = width/2.0f;
125bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            mCenterY = height/2.0f;
126bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            drawFrame();
127bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        }
128bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen
129bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        @Override
130bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        public void onSurfaceCreated(SurfaceHolder holder) {
131bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            super.onSurfaceCreated(holder);
132bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        }
133bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen
134bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        @Override
135bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        public void onSurfaceDestroyed(SurfaceHolder holder) {
136bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            super.onSurfaceDestroyed(holder);
137bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            mVisible = false;
138bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            mHandler.removeCallbacks(mDrawCube);
139bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        }
140bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen
141bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        @Override
142af20a0f6ea8460d3d33b1d3dab405eeab3862c4cMarco Nelissen        public void onOffsetsChanged(float xOffset, float yOffset,
143af20a0f6ea8460d3d33b1d3dab405eeab3862c4cMarco Nelissen                float xStep, float yStep, int xPixels, int yPixels) {
144bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            mOffset = xOffset;
145bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            drawFrame();
146bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        }
147bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen
148bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        @Override
149bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        public void onTouchEvent(MotionEvent event) {
150bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            // touch events don't actually work for wallpapers, but if they did,
151bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            // we'd be using them to draw a circle around the touch point
152bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            if (event.getAction() == MotionEvent.ACTION_MOVE) {
153bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen                mTouchX = event.getX();
154bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen                mTouchY = event.getY();
155bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            } else {
156bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen                mTouchX = -1;
157bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen                mTouchY = -1;
158bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            }
159bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            super.onTouchEvent(event);
160bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        }
161bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen
162bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        void drawFrame() {
163bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            final SurfaceHolder holder = getSurfaceHolder();
164bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            final Rect frame = holder.getSurfaceFrame();
165bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            final int width = frame.width();
166bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            final int height = frame.height();
167bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen
168bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            Canvas c = null;
169bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            try {
170bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen                c = holder.lockCanvas();
171bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen                if (c != null) {
172bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen                    // draw something
173bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen                    drawCube(c);
174bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen                    drawTouchPoint(c);
175bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen                }
176bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            } finally {
177bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen                if (c != null) holder.unlockCanvasAndPost(c);
178bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            }
179bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen
180bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            mHandler.removeCallbacks(mDrawCube);
181bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            if (mVisible) {
182bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen                mHandler.postDelayed(mDrawCube, 1000 / 25);
183bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            }
184bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        }
185bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen
186bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        void drawCube(Canvas c) {
187bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            c.save();
188bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            c.drawColor(0xff000000);
189bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen
190f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent            if (mAudioCapture != null) {
191f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                mVizData = mAudioCapture.getFormattedData(1, 1);
192f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent            } else {
193f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                Arrays.fill(mVizData, (int)0);
194f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent            }
195bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen
196bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            for (int i = 0; i < mWidth; i++) {
197f6b1bdc03ede37217da23aafeb55ab8635ccaaefEric Laurent                c.drawPoint(i, mCenterY + mVizData[i], mPaint);
198bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            }
199bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            c.restore();
200bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        }
201bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen
202bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        void drawTouchPoint(Canvas c) {
203bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            if (mTouchX >=0 && mTouchY >= 0) {
204bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen                c.drawCircle(mTouchX, mTouchY, 50, mPaint);
205bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen            }
206bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen        }
207bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen
208bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen    }
209bb362b27cbcccf8f845e6ec83d0540b477fece08Marco Nelissen}
210