Home | History | Annotate | Download | only in graphics
      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
     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
     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
     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
     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 
     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 
     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 
     79     public void surfaceRedrawNeeded(SurfaceHolder holder) {
     80     }
     81 
     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 
    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 
    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 
    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 
    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
    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