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