Add new demo of taking over a window's surface.

Change-Id: If76f577d2a314018d7dc7980ffa446b7cf050037
diff --git a/samples/AliasActivity/AndroidManifest.xml b/samples/AliasActivity/AndroidManifest.xml
index 33ad326..66ff9f2 100644
--- a/samples/AliasActivity/AndroidManifest.xml
+++ b/samples/AliasActivity/AndroidManifest.xml
@@ -21,8 +21,8 @@
      to come from a domain that you own or have control over. -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.example.android.aliasactivity">
-    <application android:hasCode="false">
-        <activity android:name="android.app.AliasActivity" android:label="@string/app_label">
+    <application android:hasCode="false" android:label="@string/app_label">
+        <activity android:name="android.app.AliasActivity">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
                 <category android:name="android.intent.category.LAUNCHER"/>
diff --git a/samples/ApiDemos/AndroidManifest.xml b/samples/ApiDemos/AndroidManifest.xml
index 1e3f66b..e3eca81 100644
--- a/samples/ApiDemos/AndroidManifest.xml
+++ b/samples/ApiDemos/AndroidManifest.xml
@@ -1605,6 +1605,14 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".graphics.WindowSurface"
+                android:label="Graphics/Surface Window">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.SAMPLE_CODE" />
+            </intent-filter>
+        </activity>
+
         <activity android:name=".graphics.TextAlign" android:label="Graphics/Text Align">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
diff --git a/samples/ApiDemos/src/com/example/android/apis/graphics/WindowSurface.java b/samples/ApiDemos/src/com/example/android/apis/graphics/WindowSurface.java
new file mode 100644
index 0000000..c7b03c1
--- /dev/null
+++ b/samples/ApiDemos/src/com/example/android/apis/graphics/WindowSurface.java
@@ -0,0 +1,264 @@
+package com.example.android.apis.graphics;
+
+import android.app.Activity;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.SurfaceHolder;
+
+/**
+ * Demonstrates how to take over the Surface from a window to do direct
+ * drawing to it (without going through the view hierarchy).
+ */
+public class WindowSurface extends Activity implements SurfaceHolder.Callback {
+    DrawingThread mDrawingThread;
+    
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        
+        // Tell the activity's window that we want to do our own drawing
+        // to its surface.  This prevents the view hierarchy from drawing to
+        // it, though we can still add views to capture input if desired.
+        getWindow().takeSurface(this);
+        
+        // This is the thread that will be drawing to our surface.
+        mDrawingThread = new DrawingThread();
+        mDrawingThread.start();
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+        
+        // Make sure the drawing thread is not running while we are paused.
+        synchronized (mDrawingThread) {
+            mDrawingThread.mRunning = false;
+            mDrawingThread.notify();
+        }
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+        
+        // Let the drawing thread resume running.
+        synchronized (mDrawingThread) {
+            mDrawingThread.mRunning = true;
+            mDrawingThread.notify();
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        
+        // Make sure the drawing thread goes away.
+        synchronized (mDrawingThread) {
+            mDrawingThread.mQuit = true;
+            mDrawingThread.notify();
+        }
+    }
+
+    public void surfaceCreated(SurfaceHolder holder) {
+        // Tell the drawing thread that a surface is available.
+        synchronized (mDrawingThread) {
+            mDrawingThread.mSurface = holder;
+            mDrawingThread.notify();
+        }
+    }
+
+    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+        // Don't need to do anything here; the drawing thread will pick up
+        // new sizes from the canvas.
+    }
+
+    public void surfaceDestroyed(SurfaceHolder holder) {
+        // We need to tell the drawing thread to stop, and block until
+        // it has done so.
+        synchronized (mDrawingThread) {
+            mDrawingThread.mSurface = holder;
+            mDrawingThread.notify();
+            while (mDrawingThread.mActive) {
+                try {
+                    mDrawingThread.wait();
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+    // Tracking of a single point that is moving on the screen.
+    static final class MovingPoint {
+        float x, y, dx, dy;
+        
+        void init(int width, int height, float minStep) {
+            x = (float)((width-1)*Math.random());
+            y = (float)((height-1)*Math.random());
+            dx = (float)(Math.random()*minStep*2) + 1;
+            dy = (float)(Math.random()*minStep*2) + 1;
+        }
+        
+        float adjDelta(float cur, float minStep, float maxStep) {
+            cur += (Math.random()*minStep) - (minStep/2);
+            if (cur < 0 && cur > -minStep) cur = -minStep;
+            if (cur >= 0 && cur < minStep) cur = minStep;
+            if (cur > maxStep) cur = maxStep;
+            if (cur < -maxStep) cur = -maxStep;
+            return cur;
+        }
+        
+        void step(int width, int height, float minStep, float maxStep) {
+            x += dx;
+            if (x <= 0 || x >= (width-1)) {
+                dx = adjDelta(-dx, minStep, maxStep);
+            }
+            y += dy;
+            if (y <= 0 || y >= (height-1)) {
+                dy = adjDelta(-dy, minStep, maxStep);
+            }
+        }
+    }
+    
+    /**
+     * This is a thread that will be running a loop, drawing into the
+     * window's surface.
+     */
+    class DrawingThread extends Thread {
+        // These are protected by the Thread's lock.
+        SurfaceHolder mSurface;
+        boolean mRunning;
+        boolean mActive;
+        boolean mQuit;
+        
+        // Internal state.
+        int mLineWidth;
+        float mMinStep;
+        float mMaxStep;
+        
+        boolean mInitialized;
+        final MovingPoint mPoint1 = new MovingPoint();
+        final MovingPoint mPoint2 = new MovingPoint();
+        
+        static final int NUM_OLD = 100;
+        int mNumOld = 0;
+        final float[] mOld = new float[NUM_OLD*4];
+        final int[] mOldColor = new int[NUM_OLD];
+        int mBrightLine = 0;
+        
+        // X is red, Y is blue.
+        final MovingPoint mColor = new MovingPoint();
+        
+        final Paint mBackground = new Paint();
+        final Paint mForeground = new Paint();
+        
+        int makeGreen(int index) {
+            int dist = Math.abs(mBrightLine-index);
+            if (dist > 10) return 0;
+            return (255-(dist*(255/10))) << 8;
+        }
+        
+        @Override
+        public void run() {
+            mLineWidth = (int)(getResources().getDisplayMetrics().density * 1.5);
+            if (mLineWidth < 1) mLineWidth = 1;
+            mMinStep = mLineWidth * 2;
+            mMaxStep = mMinStep * 3;
+            
+            mBackground.setColor(0xff000000);
+            mForeground.setColor(0xff00ffff);
+            mForeground.setAntiAlias(false);
+            mForeground.setStrokeWidth(mLineWidth);
+            
+            while (true) {
+                // Synchronize with activity: block until the activity is ready
+                // and we have a surface; report whether we are active or inactive
+                // at this point; exit thread when asked to quit.
+                synchronized (this) {
+                    while (mSurface == null || !mRunning) {
+                        if (mActive) {
+                            mActive = false;
+                            notify();
+                        }
+                        if (mQuit) {
+                            return;
+                        }
+                        try {
+                            wait();
+                        } catch (InterruptedException e) {
+                        }
+                    }
+                    
+                    if (!mActive) {
+                        mActive = true;
+                        notify();
+                    }
+                    
+                    // Lock the canvas for drawing.
+                    Canvas canvas = mSurface.lockCanvas();
+                    if (canvas == null) {
+                        Log.i("WindowSurface", "Failure locking canvas");
+                        continue;
+                    }
+                    
+                    // Update graphics.
+                    if (!mInitialized) {
+                        mInitialized = true;
+                        mPoint1.init(canvas.getWidth(), canvas.getHeight(), mMinStep);
+                        mPoint2.init(canvas.getWidth(), canvas.getHeight(), mMinStep);
+                        mColor.init(127, 127, 1);
+                    } else {
+                        mPoint1.step(canvas.getWidth(), canvas.getHeight(),
+                                mMinStep, mMaxStep);
+                        mPoint2.step(canvas.getWidth(), canvas.getHeight(),
+                                mMinStep, mMaxStep);
+                        mColor.step(127, 127, 1, 3);
+                    }
+                    mBrightLine+=2;
+                    if (mBrightLine > (NUM_OLD*2)) {
+                        mBrightLine = -2;
+                    }
+                    
+                    // Clear background.
+                    canvas.drawColor(mBackground.getColor());
+                    
+                    // Draw old lines.
+                    for (int i=mNumOld-1; i>=0; i--) {
+                        mForeground.setColor(mOldColor[i] | makeGreen(i));
+                        mForeground.setAlpha(((NUM_OLD-i) * 255) / NUM_OLD);
+                        int p = i*4;
+                        canvas.drawLine(mOld[p], mOld[p+1], mOld[p+2], mOld[p+3], mForeground);
+                    }
+                    
+                    // Draw new line.
+                    int red = (int)mColor.x + 128;
+                    if (red > 255) red = 255;
+                    int blue = (int)mColor.y + 128;
+                    if (blue > 255) blue = 255;
+                    int color = 0xff000000 | (red<<16) | blue;
+                    mForeground.setColor(color | makeGreen(-2));
+                    canvas.drawLine(mPoint1.x, mPoint1.y, mPoint2.x, mPoint2.y, mForeground);
+                    
+                    // Add in the new line.
+                    if (mNumOld > 1) {
+                        System.arraycopy(mOld, 0, mOld, 4, (mNumOld-1)*4);
+                        System.arraycopy(mOldColor, 0, mOldColor, 1, mNumOld-1);
+                    }
+                    if (mNumOld < NUM_OLD) mNumOld++;
+                    mOld[0] = mPoint1.x;
+                    mOld[1] = mPoint1.y;
+                    mOld[2] = mPoint2.x;
+                    mOld[3] = mPoint2.y;
+                    mOldColor[0] = color;
+                    
+                    // All done!
+                    mSurface.unlockCanvasAndPost(canvas);
+                }
+            }
+        }
+    }
+}