Index: src/com/example/advancewars/GameView.java
===================================================================
--- src/com/example/advancewars/GameView.java	(revision 5d9e7bb16ff8265f4388276fc3d0d3e4f9f78923)
+++ src/com/example/advancewars/GameView.java	(revision 5d9e7bb16ff8265f4388276fc3d0d3e4f9f78923)
@@ -0,0 +1,454 @@
+package com.example.advancewars;
+
+import java.util.*;
+
+import android.content.Context;
+import android.graphics.*;
+import android.os.*;
+import android.view.*;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.widget.TextView;
+
+/**
+ * View that draws, takes keystrokes, etc. for a simple LunarLander game.
+ * 
+ * Has a mode which RUNNING, PAUSED, etc. Has a x, y, dx, dy, ... capturing the
+ * current ship physics. All x/y etc. are measured with (0,0) at the lower left.
+ * updatePhysics() advances the physics based on realtime. draw() renders the
+ * ship, and does an invalidate() to prompt another draw() as soon as possible
+ * by the system.
+ */
+class GameView extends SurfaceView implements SurfaceHolder.Callback {
+	
+    class DrawingThread extends Thread {        
+        public AppState mAppState;
+        public GameState mGameState;
+
+        /*
+         * UI constants (i.e. the speed & fuel bars)
+         */
+        public static final int UI_BAR = 100; // width of the bar(s)
+        public static final int UI_BAR_HEIGHT = 10; // height of the bar(s)
+
+        /*
+         * Member (state) fields
+         */
+
+        private int mCanvasHeight = 1;
+        private int mCanvasWidth = 1;
+        public int mPlayerWins = 0, mPlayerLosses = 0;
+
+        /** Message handler used by thread to interact with TextView */
+        private Handler mHandler;
+
+        /** Used to figure out elapsed time between frames */
+        private long mLastTime;
+
+        /** Paint to draw the lines on screen. */
+        private Paint mLinePaint, mTextPaint, mButtonPaint;
+
+        /** Indicate whether the surface has been created & is ready to draw */
+        private boolean mRun = false;
+
+        /** Handle to the surface manager object we interact with */
+        private SurfaceHolder mSurfaceHolder;
+        
+        public DrawingThread(SurfaceHolder surfaceHolder, Context context,
+                Handler handler) {
+            // get handles to some important objects
+            mSurfaceHolder = surfaceHolder;
+            mHandler = handler;
+            mContext = context;
+
+            // Initialize paints for speedometer
+            mLinePaint = new Paint();
+            mLinePaint.setAntiAlias(true);
+            mLinePaint.setARGB(255, 0, 255, 0);
+
+            mTextPaint = new Paint();
+            mTextPaint.setAntiAlias(true);
+            mTextPaint.setARGB(255, 255, 255, 255);
+            mTextPaint.setTextSize(12);
+            
+            mButtonPaint = new Paint();
+            mButtonPaint.setAntiAlias(true);
+            mButtonPaint.setARGB(255, 0, 0, 0);
+            mButtonPaint.setTextSize(20);
+            mButtonPaint.setTextAlign(Paint.Align.CENTER);
+            
+            mGameState = GameState.YOUR_TURN;
+        }
+        
+        /**
+         * Starts the game, setting parameters for the current difficulty.
+         */
+        // I don't think this gets called now. maybe we should call it in the thread constructor
+        public void doStart() {
+            synchronized (mSurfaceHolder) {
+                mLastTime = System.currentTimeMillis() + 100;
+                setState(AppState.RUNNING);
+                Log.i("Blackjack", "Player's turn starting now");
+                mGameState = GameState.YOUR_TURN;
+            }
+        }
+
+        /**
+         * Pauses the physics update & animation.
+         */
+        public void pause() {
+            synchronized (mSurfaceHolder) {
+                if (mAppState == AppState.RUNNING) setState(AppState.PAUSE);
+            }
+        }
+
+        @Override
+        public void run() {
+            while (mRun) {
+                Canvas c = null;
+                try {
+                    c = mSurfaceHolder.lockCanvas(null);
+                    synchronized(mSurfaceHolder) {
+                        if(mAppState == AppState.RUNNING)
+                        	updatePhysics();
+                        doDraw(c);
+                    }
+                } finally {
+                    // do this in a finally so that if an exception is thrown
+                    // during the above, we don't leave the Surface in an
+                    // inconsistent state
+                    if (c != null) {
+                        mSurfaceHolder.unlockCanvasAndPost(c);
+                    }
+                }
+            }
+        }
+
+        /**
+         * Used to signal the thread whether it should be running or not.
+         * Passing true allows the thread to run; passing false will shut it
+         * down if it's already running. Calling start() after this was most
+         * recently called with false will result in an immediate shutdown.
+         * 
+         * @param b true to run, false to shut down
+         */
+        public void setRunning(boolean b) {
+            mRun = b;
+        }
+
+        /**
+         * Sets the game mode. That is, whether we are running, paused, in the
+         * failure state, in the victory state, etc.
+         * 
+         * @see #setState(int, CharSequence)
+         * @param mode one of the STATE_* constants
+         */
+        public void setState(AppState state) {
+            synchronized (mSurfaceHolder) {
+                setState(state, null);
+            }
+        }
+        
+        public void setGameState(GameState state) {
+            synchronized (mSurfaceHolder) {
+                mGameState = state;
+            }
+        }
+
+        /**
+         * Sets the game mode. That is, whether we are running, paused, in the
+         * failure state, in the victory state, etc.
+         * 
+         * @param mode one of the STATE_* constants
+         * @param message string to add to screen or null
+         */
+        public void setState(AppState mode, CharSequence message) {
+            /*
+             * This method optionally can cause a text message to be displayed
+             * to the user when the mode changes. Since the View that actually
+             * renders that text is part of the main View hierarchy and not
+             * owned by this thread, we can't touch the state of that View.
+             * Instead we use a Message + Handler to relay commands to the main
+             * thread, which updates the user-text View.
+             */
+            synchronized (mSurfaceHolder) {
+            	mAppState = mode;
+
+                if (mAppState == AppState.RUNNING) {
+                    Message msg = mHandler.obtainMessage();
+                    Bundle b = new Bundle();
+                    b.putString("text", "");
+                    b.putInt("viz", GameView.INVISIBLE);
+                    msg.setData(b);
+                    mHandler.sendMessage(msg);
+                } else {
+                    CharSequence str = "";
+                    str = "Mode probably changed";
+
+                    if (message != null) {
+                        str = message + "\n" + str;
+                    }
+
+                    Message msg = mHandler.obtainMessage();
+                    Bundle b = new Bundle();
+                    b.putString("text", str.toString());
+                    b.putInt("viz", GameView.VISIBLE);
+                    msg.setData(b);
+                    //mHandler.sendMessage(msg);
+                }
+            }
+        }
+        
+        /* Callback invoked when the surface dimensions change. */
+        public void setSurfaceSize(int width, int height) {
+            // synchronized to make sure these all change atomically
+            synchronized (mSurfaceHolder) {
+                mCanvasWidth = width;
+                mCanvasHeight = height;
+                
+                Log.i("Blackjack", "width: "+mCanvasWidth+", height: "+mCanvasHeight);
+            }
+        }
+
+        /**
+         * Resumes from a pause.
+         */
+        public void unpause() {
+            // Move the real time clock up to now
+            synchronized (mSurfaceHolder) {
+                mLastTime = System.currentTimeMillis() + 100;
+            }
+            setState(AppState.RUNNING);
+        }
+
+        /**
+         * Handles a key-down event.
+         * 
+         * @param keyCode the key that was pressed
+         * @param msg the original event object
+         * @return true
+         */
+        boolean doKeyDown(int keyCode, KeyEvent msg) {
+            synchronized (mSurfaceHolder) {
+                boolean okStart = false;
+                if (keyCode == KeyEvent.KEYCODE_DPAD_UP) okStart = true;
+                if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) okStart = true;
+                if (keyCode == KeyEvent.KEYCODE_S) okStart = true;
+
+                if (okStart
+                        && (mAppState == AppState.READY || mAppState == AppState.LOSE || mAppState == AppState.WIN)) {
+                    // ready-to-start -> start
+                    doStart();
+                    return true;
+                } else if (mAppState == AppState.PAUSE && okStart) {
+                    // paused -> running
+                    unpause();
+                    return true;
+                } else if (mAppState == AppState.RUNNING) {
+                    return true;
+                }
+
+                return false;
+            }
+        }
+
+        /**
+         * Handles a key-up event.
+         * 
+         * @param keyCode the key that was pressed
+         * @param msg the original event object
+         * @return true if the key was handled and consumed, or else false
+         */
+        boolean doKeyUp(int keyCode, KeyEvent msg) {
+            boolean handled = false;
+
+            synchronized (mSurfaceHolder) {
+                if (mAppState == AppState.RUNNING) {
+                    if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER
+                            || keyCode == KeyEvent.KEYCODE_SPACE) {
+                        handled = true;
+                    } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT
+                            || keyCode == KeyEvent.KEYCODE_Q
+                            || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT
+                            || keyCode == KeyEvent.KEYCODE_W) {
+                        handled = true;
+                    }
+                }
+            }
+
+            return handled;
+        }
+
+        /**
+         * Draws the ship, fuel/speed bars, and background to the provided
+         * Canvas.
+         */
+        private void doDraw(Canvas canvas) {
+        	canvas.drawColor(Color.BLACK);
+        	
+        	mTextPaint.setTextSize(12);
+        	Paint.FontMetrics metrics = mTextPaint.getFontMetrics();
+        	
+        	String text = "Your Total: ";
+        	canvas.drawText(text, 40-mTextPaint.measureText(text)/2, 450-(metrics.ascent+metrics.descent)/2, mTextPaint);
+        	
+        	text = "Dealer Total: ";
+        	canvas.drawText(text, 125-mTextPaint.measureText(text)/2, 450-(metrics.ascent+metrics.descent)/2, mTextPaint);
+        	
+        	text = mPlayerWins+" wins - "+mPlayerLosses+" losses";
+        	canvas.drawText(text, 270-mTextPaint.measureText(text)/2, 450-(metrics.ascent+metrics.descent)/2, mTextPaint);
+        }
+
+        /**
+         * Figures the lander state (x, y, fuel, ...) based on the passage of
+         * realtime. Does not invalidate(). Called at the start of draw().
+         * Detects the end-of-game and sets the UI to the next state.
+         */
+        private void updatePhysics() {
+            long now = System.currentTimeMillis();
+
+            // Do nothing if mLastTime is in the future.
+            // This allows the game-start to delay the start of the physics
+            // by 100ms or whatever.
+            if (mLastTime > now) return;
+            
+            // DO SHIT HERE
+
+            mLastTime = now+50;
+        }
+    }
+
+    /** Handle to the application context, used to e.g. fetch Drawables. */
+    private Context mContext;
+
+    /** Pointer to the text view to display "Paused.." etc. */
+    private TextView mStatusText;
+
+    /** The thread that actually draws the animation */
+    private DrawingThread thread;
+
+    public GameView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        // register our interest in hearing about changes to our surface
+        SurfaceHolder holder = getHolder();
+        holder.addCallback(this);
+
+        // create thread only; it's started in surfaceCreated()
+        thread = new DrawingThread(holder, context, new Handler() {
+            @Override
+            public void handleMessage(Message m) {
+                mStatusText.setVisibility(m.getData().getInt("viz"));
+                mStatusText.setText(m.getData().getString("text"));
+            }
+        });
+
+        setFocusable(true); // make sure we get key events
+    }
+    
+    public void newRound() {        
+        thread.mGameState = GameState.YOUR_TURN;        
+    }
+
+    @Override public boolean onTouchEvent(MotionEvent event) {
+    	Log.i("Blackjack", "Detected touch event");
+    	
+    	if(event.getAction() == MotionEvent.ACTION_UP) {
+    		Log.i("Blackjack", "Detected UP touch action");
+    		switch(thread.mGameState) {
+    		case YOUR_TURN:
+    			Log.i("Blackjack", "Player's turn");
+    			break;
+    		case COMP_TURN:
+    			Log.i("Blackjack", "Computer's turn");
+    			break;
+    		}
+    	}else if(event.getAction() == MotionEvent.ACTION_DOWN) {
+	    	
+    	}
+        
+        return true;
+    }
+    
+    /**
+     * Fetches the animation thread corresponding to this LunarView.
+     * 
+     * @return the animation thread
+     */
+    public DrawingThread getThread() {
+        return thread;
+    }
+
+    /**
+     * Standard override to get key-press events.
+     */
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent msg) {
+        return thread.doKeyDown(keyCode, msg);
+    }
+
+    /**
+     * Standard override for key-up. We actually care about these, so we can
+     * turn off the engine or stop rotating.
+     */
+    @Override
+    public boolean onKeyUp(int keyCode, KeyEvent msg) {
+        return thread.doKeyUp(keyCode, msg);
+    }
+
+    /**
+     * Standard window-focus override. Notice focus lost so we can pause on
+     * focus lost. e.g. user switches to take a call.
+     */
+    @Override
+    public void onWindowFocusChanged(boolean hasWindowFocus) {
+        if (!hasWindowFocus) thread.pause();
+    }
+
+    /**
+     * Installs a pointer to the text view used for messages.
+     */
+    public void setTextView(TextView textView) {
+        mStatusText = textView;
+    }
+
+    /* Callback invoked when the surface dimensions change. */
+    public void surfaceChanged(SurfaceHolder holder, int format, int width,
+            int height) {
+        thread.setSurfaceSize(width, height);
+    }
+
+    /*
+     * Callback invoked when the Surface has been created and is ready to be
+     * used.
+     */
+    public void surfaceCreated(SurfaceHolder holder) {
+        // start the thread here so that we don't busy-wait in run()
+        // waiting for the surface to be created
+        thread.setRunning(true);
+        
+        //if(thread.mAppState == AppState.PAUSE)
+        	//thread.unpause();
+        //else
+        	thread.start();
+    }
+
+    /*
+     * Callback invoked when the Surface has been destroyed and must no longer
+     * be touched. WARNING: after this method returns, the Surface/Canvas must
+     * never be touched again!
+     */
+    public void surfaceDestroyed(SurfaceHolder holder) {
+        // we have to tell thread to shut down & wait for it to finish, or else
+        // it might touch the Surface after we return and explode
+        boolean retry = true;
+        thread.setRunning(false);
+        while (retry) {
+            try {
+                thread.join();
+                retry = false;
+            } catch (InterruptedException e) {
+            }
+        }
+    }
+}
