1 package com.example.android.apis.graphics;
2 
3 import android.app.Activity;
4 import android.graphics.Canvas;
5 import android.graphics.Paint;
6 import android.os.Bundle;
7 import android.util.Log;
8 import android.view.KeyEvent;
9 import android.view.MotionEvent;
10 import android.view.SurfaceHolder;
11 
12 /**
13  * Demonstrates how to take over the Surface from a window to do direct
14  * drawing to it (without going through the view hierarchy).
15  */
16 public class WindowSurface extends Activity implements SurfaceHolder.Callback2 {
17     DrawingThread mDrawingThread;
18 
19     @Override
onCreate(Bundle savedInstanceState)20     protected void onCreate(Bundle savedInstanceState) {
21         super.onCreate(savedInstanceState);
22 
23         // Tell the activity's window that we want to do our own drawing
24         // to its surface.  This prevents the view hierarchy from drawing to
25         // it, though we can still add views to capture input if desired.
26         getWindow().takeSurface(this);
27 
28         // This is the thread that will be drawing to our surface.
29         mDrawingThread = new DrawingThread();
30         mDrawingThread.start();
31     }
32 
33     @Override
onPause()34     protected void onPause() {
35         super.onPause();
36 
37         // Make sure the drawing thread is not running while we are paused.
38         synchronized (mDrawingThread) {
39             mDrawingThread.mRunning = false;
40             mDrawingThread.notify();
41         }
42     }
43 
44     @Override
onResume()45     protected void onResume() {
46         super.onResume();
47 
48         // Let the drawing thread resume running.
49         synchronized (mDrawingThread) {
50             mDrawingThread.mRunning = true;
51             mDrawingThread.notify();
52         }
53     }
54 
55     @Override
onDestroy()56     protected void onDestroy() {
57         super.onDestroy();
58 
59         // Make sure the drawing thread goes away.
60         synchronized (mDrawingThread) {
61             mDrawingThread.mQuit = true;
62             mDrawingThread.notify();
63         }
64     }
65 
surfaceCreated(SurfaceHolder holder)66     public void surfaceCreated(SurfaceHolder holder) {
67         // Tell the drawing thread that a surface is available.
68         synchronized (mDrawingThread) {
69             mDrawingThread.mSurface = holder;
70             mDrawingThread.notify();
71         }
72     }
73 
surfaceChanged(SurfaceHolder holder, int format, int width, int height)74     public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
75         // Don't need to do anything here; the drawing thread will pick up
76         // new sizes from the canvas.
77     }
78 
surfaceRedrawNeeded(SurfaceHolder holder)79     public void surfaceRedrawNeeded(SurfaceHolder holder) {
80     }
81 
surfaceDestroyed(SurfaceHolder holder)82     public void surfaceDestroyed(SurfaceHolder holder) {
83         // We need to tell the drawing thread to stop, and block until
84         // it has done so.
85         synchronized (mDrawingThread) {
86             mDrawingThread.mSurface = holder;
87             mDrawingThread.notify();
88             while (mDrawingThread.mActive) {
89                 try {
90                     mDrawingThread.wait();
91                 } catch (InterruptedException e) {
92                     e.printStackTrace();
93                 }
94             }
95         }
96     }
97 
98     // Tracking of a single point that is moving on the screen.
99     static final class MovingPoint {
100         float x, y, dx, dy;
101 
init(int width, int height, float minStep)102         void init(int width, int height, float minStep) {
103             x = (float)((width-1)*Math.random());
104             y = (float)((height-1)*Math.random());
105             dx = (float)(Math.random()*minStep*2) + 1;
106             dy = (float)(Math.random()*minStep*2) + 1;
107         }
108 
adjDelta(float cur, float minStep, float maxStep)109         float adjDelta(float cur, float minStep, float maxStep) {
110             cur += (Math.random()*minStep) - (minStep/2);
111             if (cur < 0 && cur > -minStep) cur = -minStep;
112             if (cur >= 0 && cur < minStep) cur = minStep;
113             if (cur > maxStep) cur = maxStep;
114             if (cur < -maxStep) cur = -maxStep;
115             return cur;
116         }
117 
step(int width, int height, float minStep, float maxStep)118         void step(int width, int height, float minStep, float maxStep) {
119             x += dx;
120             if (x <= 0 || x >= (width-1)) {
121                 if (x <= 0) x = 0;
122                 else if (x >= (width-1)) x = width-1;
123                 dx = adjDelta(-dx, minStep, maxStep);
124             }
125             y += dy;
126             if (y <= 0 || y >= (height-1)) {
127                 if (y <= 0) y = 0;
128                 else if (y >= (height-1)) y = height-1;
129                 dy = adjDelta(-dy, minStep, maxStep);
130             }
131         }
132     }
133 
134     /**
135      * This is a thread that will be running a loop, drawing into the
136      * window's surface.
137      */
138     class DrawingThread extends Thread {
139         // These are protected by the Thread's lock.
140         SurfaceHolder mSurface;
141         boolean mRunning;
142         boolean mActive;
143         boolean mQuit;
144 
145         // Internal state.
146         int mLineWidth;
147         float mMinStep;
148         float mMaxStep;
149 
150         boolean mInitialized;
151         final MovingPoint mPoint1 = new MovingPoint();
152         final MovingPoint mPoint2 = new MovingPoint();
153 
154         static final int NUM_OLD = 100;
155         int mNumOld = 0;
156         final float[] mOld = new float[NUM_OLD*4];
157         final int[] mOldColor = new int[NUM_OLD];
158         int mBrightLine = 0;
159 
160         // X is red, Y is blue.
161         final MovingPoint mColor = new MovingPoint();
162 
163         final Paint mBackground = new Paint();
164         final Paint mForeground = new Paint();
165 
makeGreen(int index)166         int makeGreen(int index) {
167             int dist = Math.abs(mBrightLine-index);
168             if (dist > 10) return 0;
169             return (255-(dist*(255/10))) << 8;
170         }
171 
172         @Override
run()173         public void run() {
174             mLineWidth = (int)(getResources().getDisplayMetrics().density * 1.5);
175             if (mLineWidth < 1) mLineWidth = 1;
176             mMinStep = mLineWidth * 2;
177             mMaxStep = mMinStep * 3;
178 
179             mBackground.setColor(0xff000000);
180             mForeground.setColor(0xff00ffff);
181             mForeground.setAntiAlias(false);
182             mForeground.setStrokeWidth(mLineWidth);
183 
184             while (true) {
185                 // Synchronize with activity: block until the activity is ready
186                 // and we have a surface; report whether we are active or inactive
187                 // at this point; exit thread when asked to quit.
188                 synchronized (this) {
189                     while (mSurface == null || !mRunning) {
190                         if (mActive) {
191                             mActive = false;
192                             notify();
193                         }
194                         if (mQuit) {
195                             return;
196                         }
197                         try {
198                             wait();
199                         } catch (InterruptedException e) {
200                         }
201                     }
202 
203                     if (!mActive) {
204                         mActive = true;
205                         notify();
206                     }
207 
208                     // Lock the canvas for drawing.
209                     Canvas canvas = mSurface.lockCanvas();
210                     if (canvas == null) {
211                         Log.i("WindowSurface", "Failure locking canvas");
212                         continue;
213                     }
214 
215                     // Update graphics.
216                     if (!mInitialized) {
217                         mInitialized = true;
218                         mPoint1.init(canvas.getWidth(), canvas.getHeight(), mMinStep);
219                         mPoint2.init(canvas.getWidth(), canvas.getHeight(), mMinStep);
220                         mColor.init(127, 127, 1);
221                     } else {
222                         mPoint1.step(canvas.getWidth(), canvas.getHeight(),
223                                 mMinStep, mMaxStep);
224                         mPoint2.step(canvas.getWidth(), canvas.getHeight(),
225                                 mMinStep, mMaxStep);
226                         mColor.step(127, 127, 1, 3);
227                     }
228                     mBrightLine+=2;
229                     if (mBrightLine > (NUM_OLD*2)) {
230                         mBrightLine = -2;
231                     }
232 
233                     // Clear background.
234                     canvas.drawColor(mBackground.getColor());
235 
236                     // Draw old lines.
237                     for (int i=mNumOld-1; i>=0; i--) {
238                         mForeground.setColor(mOldColor[i] | makeGreen(i));
239                         mForeground.setAlpha(((NUM_OLD-i) * 255) / NUM_OLD);
240                         int p = i*4;
241                         canvas.drawLine(mOld[p], mOld[p+1], mOld[p+2], mOld[p+3], mForeground);
242                     }
243 
244                     // Draw new line.
245                     int red = (int)mColor.x + 128;
246                     if (red > 255) red = 255;
247                     int blue = (int)mColor.y + 128;
248                     if (blue > 255) blue = 255;
249                     int color = 0xff000000 | (red<<16) | blue;
250                     mForeground.setColor(color | makeGreen(-2));
251                     canvas.drawLine(mPoint1.x, mPoint1.y, mPoint2.x, mPoint2.y, mForeground);
252 
253                     // Add in the new line.
254                     if (mNumOld > 1) {
255                         System.arraycopy(mOld, 0, mOld, 4, (mNumOld-1)*4);
256                         System.arraycopy(mOldColor, 0, mOldColor, 1, mNumOld-1);
257                     }
258                     if (mNumOld < NUM_OLD) mNumOld++;
259                     mOld[0] = mPoint1.x;
260                     mOld[1] = mPoint1.y;
261                     mOld[2] = mPoint2.x;
262                     mOld[3] = mPoint2.y;
263                     mOldColor[0] = color;
264 
265                     // All done!
266                     mSurface.unlockCanvasAndPost(canvas);
267                 }
268             }
269         }
270     }
271 }
272