Modified Snake Sample app to run on non-touch devices like Google Tv and also devices with no dpad support

2D canvas DrawVertex to create a vector graphic background
touch & keypad playable
landscape & portrait for all known device sizes.  All measurements in DP and nicely scaling.
using xml drawables to rotate "dpad" arrow

Change-Id: I995acaaf0935c13c03fcbcf974ce5af06f46780e
diff --git a/samples/Snake/AndroidManifest.xml b/samples/Snake/AndroidManifest.xml
index 36a9939..757a2d6 100644
--- a/samples/Snake/AndroidManifest.xml
+++ b/samples/Snake/AndroidManifest.xml
@@ -14,22 +14,31 @@
      limitations under the License.
 -->
 
-<!-- Declare the contents of this Android application.  The namespace
-     attribute brings in the Android platform namespace, and the package
-     supplies a unique name for the application.  When writing your
-     own application, the package name must be changed from "com.example.*"
-     to come from a domain that you own or have control over. -->
+<!-- Declare the contents of this Android application. The namespace attribute 
+  brings in the Android platform namespace, and the package supplies a unique 
+  name for the application. When writing your own application, the package 
+  name must be changed from "com.example.*" 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.snake">
-    <application android:label="Snake on a Phone">
-      <activity android:name="Snake"
-        android:theme="@android:style/Theme.NoTitleBar"
-        android:screenOrientation="portrait"
-        android:configChanges="keyboardHidden|orientation">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest> 
+  package="com.example.android.snake">
+
+  <uses-sdk android:minSdkVersion="3" android:targetSdkVersion="15" />
+  <!-- Declares that the app supports devices w/o touch, such as a Google TV device -->
+  <uses-feature android:name="android.hardware.touchscreen"
+    android:required="false" />
+
+  <supports-screens android:largeScreens="true" />
+
+  <application android:icon="@drawable/ic_launcher" android:label="@string/app_name">
+    <activity android:name="Snake" android:configChanges="keyboardHidden|orientation"
+      android:screenOrientation="nosensor" android:theme="@android:style/Theme.NoTitleBar">
+      <intent-filter>
+        <action android:name="android.intent.action.MAIN" />
+
+        <category android:name="android.intent.category.LAUNCHER" />
+      </intent-filter>
+    </activity>
+  </application>
+
+</manifest>
diff --git a/samples/Snake/res/drawable-hdpi/ic_launcher.png b/samples/Snake/res/drawable-hdpi/ic_launcher.png
new file mode 100755
index 0000000..b500381
--- /dev/null
+++ b/samples/Snake/res/drawable-hdpi/ic_launcher.png
Binary files differ
diff --git a/samples/Snake/res/drawable-ldpi/ic_launcher.png b/samples/Snake/res/drawable-ldpi/ic_launcher.png
new file mode 100755
index 0000000..f0efb98
--- /dev/null
+++ b/samples/Snake/res/drawable-ldpi/ic_launcher.png
Binary files differ
diff --git a/samples/Snake/res/drawable-mdpi/dpad_down.xml b/samples/Snake/res/drawable-mdpi/dpad_down.xml
new file mode 100755
index 0000000..1b635a2
--- /dev/null
+++ b/samples/Snake/res/drawable-mdpi/dpad_down.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<rotate xmlns:android="http://schemas.android.com/apk/res/android"
+        android:fromDegrees="180"
+        android:toDegrees="180"
+        android:pivotX="50%"
+        android:pivotY="50%"
+        android:drawable="@drawable/dpad_up"/>
diff --git a/samples/Snake/res/drawable-mdpi/dpad_left.xml b/samples/Snake/res/drawable-mdpi/dpad_left.xml
new file mode 100755
index 0000000..b9f9648
--- /dev/null
+++ b/samples/Snake/res/drawable-mdpi/dpad_left.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<rotate xmlns:android="http://schemas.android.com/apk/res/android"
+        android:fromDegrees="-90"
+        android:toDegrees="-90"
+        android:pivotX="50%"
+        android:pivotY="50%"
+        android:drawable="@drawable/dpad_up"/>
diff --git a/samples/Snake/res/drawable-mdpi/dpad_right.xml b/samples/Snake/res/drawable-mdpi/dpad_right.xml
new file mode 100755
index 0000000..15b35d6
--- /dev/null
+++ b/samples/Snake/res/drawable-mdpi/dpad_right.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<rotate xmlns:android="http://schemas.android.com/apk/res/android"
+   android:fromDegrees="90"
+   android:toDegrees="90"
+   android:pivotX="50%"
+   android:pivotY="50%"
+   android:drawable="@drawable/dpad_up"/>
diff --git a/samples/Snake/res/drawable-mdpi/dpad_up.png b/samples/Snake/res/drawable-mdpi/dpad_up.png
new file mode 100755
index 0000000..01d6511
--- /dev/null
+++ b/samples/Snake/res/drawable-mdpi/dpad_up.png
Binary files differ
diff --git a/samples/Snake/res/drawable/greenstar.png b/samples/Snake/res/drawable-mdpi/greenstar.png
old mode 100644
new mode 100755
similarity index 100%
rename from samples/Snake/res/drawable/greenstar.png
rename to samples/Snake/res/drawable-mdpi/greenstar.png
Binary files differ
diff --git a/samples/Snake/res/drawable-mdpi/ic_launcher.png b/samples/Snake/res/drawable-mdpi/ic_launcher.png
new file mode 100755
index 0000000..31d5bbd
--- /dev/null
+++ b/samples/Snake/res/drawable-mdpi/ic_launcher.png
Binary files differ
diff --git a/samples/Snake/res/drawable/redstar.png b/samples/Snake/res/drawable-mdpi/redstar.png
old mode 100644
new mode 100755
similarity index 100%
rename from samples/Snake/res/drawable/redstar.png
rename to samples/Snake/res/drawable-mdpi/redstar.png
Binary files differ
diff --git a/samples/Snake/res/drawable/yellowstar.png b/samples/Snake/res/drawable-mdpi/yellowstar.png
old mode 100644
new mode 100755
similarity index 100%
rename from samples/Snake/res/drawable/yellowstar.png
rename to samples/Snake/res/drawable-mdpi/yellowstar.png
Binary files differ
diff --git a/samples/Snake/res/drawable-xhdpi/ic_launcher.png b/samples/Snake/res/drawable-xhdpi/ic_launcher.png
new file mode 100755
index 0000000..46cfcbf
--- /dev/null
+++ b/samples/Snake/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/samples/Snake/res/layout/snake_layout.xml b/samples/Snake/res/layout/snake_layout.xml
old mode 100644
new mode 100755
index ef8abe3..fc35fb6
--- a/samples/Snake/res/layout/snake_layout.xml
+++ b/samples/Snake/res/layout/snake_layout.xml
@@ -4,9 +4,9 @@
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
      You may obtain a copy of the License at
-  
+
           http://www.apache.org/licenses/LICENSE-2.0
-  
+
      Unless required by applicable law or agreed to in writing, software
      distributed under the License is distributed on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -14,30 +14,70 @@
      limitations under the License.
 -->
 
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
-	android:layout_width="match_parent"
-	android:layout_height="match_parent">
-	
-	<com.example.android.snake.SnakeView
-	 android:id="@+id/snake"
-		android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                tileSize="24"
-                />
-	
-	<RelativeLayout
-		android:layout_width="match_parent"
-		android:layout_height="match_parent" >
-		
-		<TextView
-		 android:id="@+id/text"
-			android:text="@string/snake_layout_text_text"
-			android:visibility="visible"
-			android:layout_width="wrap_content"
-			android:layout_height="wrap_content"
-			android:layout_centerInParent="true"
-			android:gravity="center_horizontal"
-			android:textColor="#ff8888ff"
-			android:textSize="24sp"/>
-	</RelativeLayout>
-</FrameLayout>
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+  xmlns:app="http://schemas.android.com/apk/res/com.example.android.snake">
+
+  <com.example.android.snake.BackgroundView
+    android:id="@+id/background"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    app:colorSegmentOne="@color/muted_red"
+    app:colorSegmentTwo="@color/muted_yellow"
+    app:colorSegmentThree="@color/muted_blue"
+    app:colorSegmentFour="@color/muted_green"
+     />
+
+  <com.example.android.snake.SnakeView
+    android:id="@+id/snake"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    app:tileSize="24dp" />
+
+  <TextView android:id="@+id/text"
+  android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_gravity="center"
+    android:gravity="center"
+    android:textColor="@color/text_violet"
+    android:textSize="24sp"
+    android:visibility="visible" />
+
+  <RelativeLayout android:id="@+id/arrowContainer"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:visibility="gone">
+
+    <ImageView android:id="@+id/imageUp"
+    android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:layout_alignParentTop="true"
+      android:layout_centerHorizontal="true"
+      android:padding="20dp"
+      android:src="@drawable/dpad_up" />
+
+    <ImageView android:id="@+id/imageLeft"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:layout_alignParentLeft="true"
+      android:layout_centerVertical="true"
+      android:padding="20dp"
+      android:src="@drawable/dpad_left" />
+
+    <ImageView android:id="@+id/imageRight"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:layout_alignParentRight="true"
+      android:layout_centerVertical="true"
+      android:padding="20dp"
+      android:src="@drawable/dpad_right" />
+
+    <ImageView android:id="@+id/imageDown"
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+      android:layout_alignParentBottom="true"
+      android:layout_centerHorizontal="true"
+      android:padding="20dp"
+      android:src="@drawable/dpad_down" />
+  </RelativeLayout>
+
+</merge>
diff --git a/samples/Snake/res/values-nonav/strings.xml b/samples/Snake/res/values-nonav/strings.xml
new file mode 100755
index 0000000..5b63b12
--- /dev/null
+++ b/samples/Snake/res/values-nonav/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+  <string name="app_name">Snake</string>
+  <string name="mode_ready">Snake\nTouch Screen To Play</string>
+  <string name="mode_pause">Paused\nTouch Screen To Resume</string>
+  <string name="mode_lose">Game Over\nScore: %1$d \nTouch Screen To Play</string>
+</resources>
diff --git a/samples/Snake/res/values/attrs.xml b/samples/Snake/res/values/attrs.xml
old mode 100644
new mode 100755
index c846864..6f1d1b4
--- a/samples/Snake/res/values/attrs.xml
+++ b/samples/Snake/res/values/attrs.xml
@@ -4,9 +4,9 @@
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
      You may obtain a copy of the License at
-  
+
           http://www.apache.org/licenses/LICENSE-2.0
-  
+
      Unless required by applicable law or agreed to in writing, software
      distributed under the License is distributed on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -15,8 +15,16 @@
 -->
 
 <resources>
-  <declare-styleable name="TileView">
-    <attr name="tileSize" format="integer" />
-  </declare-styleable>
-</resources>
 
+  <declare-styleable name="TileView">
+    <attr name="tileSize" format="dimension" />
+  </declare-styleable>
+  <declare-styleable name="BackgroundView">
+  <!-- Defining properties to use four different colors in 4 segments of BackgroundView -->
+    <attr name="colorSegmentOne" format="color" />
+    <attr name="colorSegmentTwo" format="color" />
+    <attr name="colorSegmentThree" format="color" />
+    <attr name="colorSegmentFour" format="color" />
+  </declare-styleable>
+
+</resources>
diff --git a/samples/Snake/res/values/colors.xml b/samples/Snake/res/values/colors.xml
new file mode 100755
index 0000000..e5d90bf
--- /dev/null
+++ b/samples/Snake/res/values/colors.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<resources>
+  <color name="muted_red">#ff400010</color>
+  <color name="muted_yellow">#ff404000</color>
+  <color name="muted_blue">#ff100050</color>
+  <color name="muted_green">#ff004000</color>
+  <color name="text_violet">#ff8888ff</color>
+  </resources>
diff --git a/samples/Snake/res/values/strings.xml b/samples/Snake/res/values/strings.xml
old mode 100644
new mode 100755
index 3c4a89d..f95ef4c
--- a/samples/Snake/res/values/strings.xml
+++ b/samples/Snake/res/values/strings.xml
@@ -4,9 +4,9 @@
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
      You may obtain a copy of the License at
-  
+
           http://www.apache.org/licenses/LICENSE-2.0
-  
+
      Unless required by applicable law or agreed to in writing, software
      distributed under the License is distributed on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -15,10 +15,8 @@
 -->
 
 <resources>
+  <string name="app_name">Snake</string>
   <string name="mode_ready">Snake\nPress Up To Play</string>
   <string name="mode_pause">Paused\nPress Up To Resume</string>
-  <string name="mode_lose_prefix">Game Over\nScore: </string>
-  <string name="mode_lose_suffix">\nPress Up To Play</string>
-
-    <string name="snake_layout_text_text"></string>
+  <string name="mode_lose">Game Over\nScore: %1$d \nPress Up To Play</string>
 </resources>
diff --git a/samples/Snake/src/com/example/android/snake/BackgroundView.java b/samples/Snake/src/com/example/android/snake/BackgroundView.java
new file mode 100755
index 0000000..bda571e
--- /dev/null
+++ b/samples/Snake/src/com/example/android/snake/BackgroundView.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.example.android.snake;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.view.View;
+
+import java.util.Arrays;
+
+/**
+ * Background View: Draw 4 full-screen RGBY triangles
+ */
+public class BackgroundView extends View {
+
+    private int[] mColors = new int[4];
+
+    private final short[] mIndices =
+            { 0, 1, 2, 0, 3, 4, 0, 1, 4 // Corner points for triangles (with offset = 2)
+    };
+
+    private float[] mVertexPoints = null;
+
+    public BackgroundView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        setFocusable(true);
+
+        // retrieve colors for 4 segments from styleable properties
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BackgroundView);
+        mColors[0] = a.getColor(R.styleable.BackgroundView_colorSegmentOne, Color.RED);
+        mColors[1] = a.getColor(R.styleable.BackgroundView_colorSegmentTwo, Color.YELLOW);
+        mColors[2] = a.getColor(R.styleable.BackgroundView_colorSegmentThree, Color.BLUE);
+        mColors[3] = a.getColor(R.styleable.BackgroundView_colorSegmentFour, Color.GREEN);
+
+        a.recycle();
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        assert(mVertexPoints != null);
+
+        // Colors for each vertex
+        int[] mFillColors = new int[mVertexPoints.length];
+
+        for (int triangle = 0; triangle < mColors.length; triangle++) {
+            // Set color for all vertex points to current triangle color
+            Arrays.fill(mFillColors, mColors[triangle]);
+
+            // Draw one triangle
+            canvas.drawVertices(Canvas.VertexMode.TRIANGLES, mVertexPoints.length, mVertexPoints,
+                    0, null, 0, // No Textures
+                    mFillColors, 0, mIndices,
+                    triangle * 2, 3, // Use 3 vertices via Index Array with offset 2
+                    new Paint());
+        }
+    }
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+
+     // Construct our center and four corners
+        mVertexPoints = new float[] {
+                w / 2, h / 2,
+                0, 0,
+                w, 0,
+                w, h,
+                0, h
+        };
+    }
+
+}
diff --git a/samples/Snake/src/com/example/android/snake/Snake.java b/samples/Snake/src/com/example/android/snake/Snake.java
old mode 100644
new mode 100755
index 6306693..ddf0c3c
--- a/samples/Snake/src/com/example/android/snake/Snake.java
+++ b/samples/Snake/src/com/example/android/snake/Snake.java
@@ -18,27 +18,38 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.view.Window;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnTouchListener;
 import android.widget.TextView;
 
 /**
  * Snake: a simple game that everyone can enjoy.
  * 
- * This is an implementation of the classic Game "Snake", in which you control a
- * serpent roaming around the garden looking for apples. Be careful, though,
- * because when you catch one, not only will you become longer, but you'll move
- * faster. Running into yourself or the walls will end the game.
+ * This is an implementation of the classic Game "Snake", in which you control a serpent roaming
+ * around the garden looking for apples. Be careful, though, because when you catch one, not only
+ * will you become longer, but you'll move faster. Running into yourself or the walls will end the
+ * game.
  * 
  */
 public class Snake extends Activity {
 
-    private SnakeView mSnakeView;
-    
+    /**
+     * Constants for desired direction of moving the snake
+     */
+    public static int MOVE_LEFT = 0;
+    public static int MOVE_UP = 1;
+    public static int MOVE_DOWN = 2;
+    public static int MOVE_RIGHT = 3;
+
     private static String ICICLE_KEY = "snake-view";
 
+    private SnakeView mSnakeView;
+
     /**
-     * Called when Activity is first created. Turns off the title bar, sets up
-     * the content views, and fires up the SnakeView.
+     * Called when Activity is first created. Turns off the title bar, sets up the content views,
+     * and fires up the SnakeView.
      * 
      */
     @Override
@@ -48,7 +59,8 @@
         setContentView(R.layout.snake_layout);
 
         mSnakeView = (SnakeView) findViewById(R.id.snake);
-        mSnakeView.setTextView((TextView) findViewById(R.id.text));
+        mSnakeView.setDependentViews((TextView) findViewById(R.id.text),
+                findViewById(R.id.arrowContainer), findViewById(R.id.background));
 
         if (savedInstanceState == null) {
             // We were just launched -- set up a new game
@@ -62,6 +74,31 @@
                 mSnakeView.setMode(SnakeView.PAUSE);
             }
         }
+        mSnakeView.setOnTouchListener(new OnTouchListener() {
+
+            @Override
+            public boolean onTouch(View v, MotionEvent event) {
+                if (mSnakeView.getGameState() == SnakeView.RUNNING) {
+                    // Normalize x,y between 0 and 1
+                    float x = event.getX() / v.getWidth();
+                    float y = event.getY() / v.getHeight();
+
+                    // Direction will be [0,1,2,3] depending on quadrant
+                    int direction = 0;
+                    direction = (x > y) ? 1 : 0;
+                    direction |= (x > 1 - y) ? 2 : 0;
+
+                    // Direction is same as the quadrant which was clicked
+                    mSnakeView.moveSnake(direction);
+
+                } else {
+                    // If the game is not running then on touching any part of the screen
+                    // we start the game by sending MOVE_UP signal to SnakeView
+                    mSnakeView.moveSnake(MOVE_UP);
+                }
+                return false;
+            }
+        });
     }
 
     @Override
@@ -73,8 +110,34 @@
 
     @Override
     public void onSaveInstanceState(Bundle outState) {
-        //Store the game state
+        // Store the game state
         outState.putBundle(ICICLE_KEY, mSnakeView.saveState());
     }
 
+    /**
+     * Handles key events in the game. Update the direction our snake is traveling based on the
+     * DPAD.
+     *
+     */
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent msg) {
+
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_UP:
+                mSnakeView.moveSnake(MOVE_UP);
+                break;
+            case KeyEvent.KEYCODE_DPAD_RIGHT:
+                mSnakeView.moveSnake(MOVE_RIGHT);
+                break;
+            case KeyEvent.KEYCODE_DPAD_DOWN:
+                mSnakeView.moveSnake(MOVE_DOWN);
+                break;
+            case KeyEvent.KEYCODE_DPAD_LEFT:
+                mSnakeView.moveSnake(MOVE_LEFT);
+                break;
+        }
+
+        return super.onKeyDown(keyCode, msg);
+    }
+
 }
diff --git a/samples/Snake/src/com/example/android/snake/SnakeView.java b/samples/Snake/src/com/example/android/snake/SnakeView.java
old mode 100644
new mode 100755
index 8dd0232..a8e654f
--- a/samples/Snake/src/com/example/android/snake/SnakeView.java
+++ b/samples/Snake/src/com/example/android/snake/SnakeView.java
@@ -16,33 +16,29 @@
 
 package com.example.android.snake;
 
-import java.util.ArrayList;
-import java.util.Random;
-
 import android.content.Context;
 import android.content.res.Resources;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
 import android.util.AttributeSet;
-import android.os.Bundle;
 import android.util.Log;
-import android.view.KeyEvent;
 import android.view.View;
 import android.widget.TextView;
 
+import java.util.ArrayList;
+import java.util.Random;
+
 /**
  * SnakeView: implementation of a simple game of Snake
- * 
- * 
  */
 public class SnakeView extends TileView {
 
     private static final String TAG = "SnakeView";
 
     /**
-     * Current mode of application: READY to run, RUNNING, or you have already
-     * lost. static final ints are used instead of an enum for performance
-     * reasons.
+     * Current mode of application: READY to run, RUNNING, or you have already lost. static final
+     * ints are used instead of an enum for performance reasons.
      */
     private int mMode = READY;
     public static final int PAUSE = 0;
@@ -68,26 +64,36 @@
     private static final int GREEN_STAR = 3;
 
     /**
-     * mScore: used to track the number of apples captured mMoveDelay: number of
-     * milliseconds between snake movements. This will decrease as apples are
-     * captured.
+     * mScore: Used to track the number of apples captured mMoveDelay: number of milliseconds
+     * between snake movements. This will decrease as apples are captured.
      */
     private long mScore = 0;
     private long mMoveDelay = 600;
     /**
-     * mLastMove: tracks the absolute time when the snake last moved, and is used
-     * to determine if a move should be made based on mMoveDelay.
+     * mLastMove: Tracks the absolute time when the snake last moved, and is used to determine if a
+     * move should be made based on mMoveDelay.
      */
     private long mLastMove;
-    
+
     /**
-     * mStatusText: text shows to the user in some run states
+     * mStatusText: Text shows to the user in some run states
      */
     private TextView mStatusText;
 
     /**
-     * mSnakeTrail: a list of Coordinates that make up the snake's body
-     * mAppleList: the secret location of the juicy apples the snake craves.
+     * mArrowsView: View which shows 4 arrows to signify 4 directions in which the snake can move
+     */
+    private View mArrowsView;
+
+    /**
+     * mBackgroundView: Background View which shows 4 different colored triangles pressing which
+     * moves the snake
+     */
+    private View mBackgroundView;
+
+    /**
+     * mSnakeTrail: A list of Coordinates that make up the snake's body mAppleList: The secret
+     * location of the juicy apples the snake craves.
      */
     private ArrayList<Coordinate> mSnakeTrail = new ArrayList<Coordinate>();
     private ArrayList<Coordinate> mAppleList = new ArrayList<Coordinate>();
@@ -98,10 +104,11 @@
     private static final Random RNG = new Random();
 
     /**
-     * Create a simple handler that we can use to cause animation to happen.  We
-     * set ourselves as a target and we can use the sleep()
-     * function to cause an update/invalidate to occur at a later date.
+     * Create a simple handler that we can use to cause animation to happen. We set ourselves as a
+     * target and we can use the sleep() function to cause an update/invalidate to occur at a later
+     * date.
      */
+
     private RefreshHandler mRedrawHandler = new RefreshHandler();
 
     class RefreshHandler extends Handler {
@@ -113,12 +120,11 @@
         }
 
         public void sleep(long delayMillis) {
-        	this.removeMessages(0);
+            this.removeMessages(0);
             sendMessageDelayed(obtainMessage(0), delayMillis);
         }
     };
 
-
     /**
      * Constructs a SnakeView based on inflation from XML
      * 
@@ -127,26 +133,26 @@
      */
     public SnakeView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        initSnakeView();
-   }
-
-    public SnakeView(Context context, AttributeSet attrs, int defStyle) {
-    	super(context, attrs, defStyle);
-    	initSnakeView();
+        initSnakeView(context);
     }
 
-    private void initSnakeView() {
+    public SnakeView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
+        initSnakeView(context);
+    }
+
+    private void initSnakeView(Context context) {
+
         setFocusable(true);
 
         Resources r = this.getContext().getResources();
-        
+
         resetTiles(4);
         loadTile(RED_STAR, r.getDrawable(R.drawable.redstar));
         loadTile(YELLOW_STAR, r.getDrawable(R.drawable.yellowstar));
         loadTile(GREEN_STAR, r.getDrawable(R.drawable.greenstar));
-    	
+
     }
-    
 
     private void initNewGame() {
         mSnakeTrail.clear();
@@ -155,7 +161,6 @@
         // For now we're just going to load up a short default eastbound snake
         // that's just turned north
 
-        
         mSnakeTrail.add(new Coordinate(7, 7));
         mSnakeTrail.add(new Coordinate(6, 7));
         mSnakeTrail.add(new Coordinate(5, 7));
@@ -172,30 +177,29 @@
         mScore = 0;
     }
 
-
     /**
-     * Given a ArrayList of coordinates, we need to flatten them into an array of
-     * ints before we can stuff them into a map for flattening and storage.
+     * Given a ArrayList of coordinates, we need to flatten them into an array of ints before we can
+     * stuff them into a map for flattening and storage.
      * 
      * @param cvec : a ArrayList of Coordinate objects
-     * @return : a simple array containing the x/y values of the coordinates
-     * as [x1,y1,x2,y2,x3,y3...]
+     * @return : a simple array containing the x/y values of the coordinates as
+     *         [x1,y1,x2,y2,x3,y3...]
      */
     private int[] coordArrayListToArray(ArrayList<Coordinate> cvec) {
-        int count = cvec.size();
-        int[] rawArray = new int[count * 2];
-        for (int index = 0; index < count; index++) {
-            Coordinate c = cvec.get(index);
-            rawArray[2 * index] = c.x;
-            rawArray[2 * index + 1] = c.y;
+        int[] rawArray = new int[cvec.size() * 2];
+
+        int i = 0;
+        for (Coordinate c : cvec) {
+            rawArray[i++] = c.x;
+            rawArray[i++] = c.y;
         }
+
         return rawArray;
     }
 
     /**
-     * Save game state so that the user does not lose anything
-     * if the game process is killed while we are in the 
-     * background.
+     * Save game state so that the user does not lose anything if the game process is killed while
+     * we are in the background.
      * 
      * @return a Bundle with this view's state
      */
@@ -213,8 +217,8 @@
     }
 
     /**
-     * Given a flattened array of ordinate pairs, we reconstitute them into a
-     * ArrayList of Coordinate objects
+     * Given a flattened array of ordinate pairs, we reconstitute them into a ArrayList of
+     * Coordinate objects
      * 
      * @param rawArray : [x1,y1,x2,y2,...]
      * @return a ArrayList of Coordinates
@@ -246,83 +250,79 @@
         mSnakeTrail = coordArrayToArrayList(icicle.getIntArray("mSnakeTrail"));
     }
 
-    /*
-     * handles key events in the game. Update the direction our snake is traveling
-     * based on the DPAD. Ignore events that would cause the snake to immediately
-     * turn back on itself.
-     * 
-     * (non-Javadoc)
-     * 
-     * @see android.view.View#onKeyDown(int, android.os.KeyEvent)
+    /**
+     * Handles snake movement triggers from Snake Activity and moves the snake accordingly. Ignore
+     * events that would cause the snake to immediately turn back on itself.
+     *
+     * @param direction The desired direction of movement
      */
-    @Override
-    public boolean onKeyDown(int keyCode, KeyEvent msg) {
+    public void moveSnake(int direction) {
 
-        if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
+        if (direction == Snake.MOVE_UP) {
             if (mMode == READY | mMode == LOSE) {
                 /*
                  * At the beginning of the game, or the end of a previous one,
-                 * we should start a new game.
+                 * we should start a new game if UP key is clicked.
                  */
                 initNewGame();
                 setMode(RUNNING);
                 update();
-                return (true);
+                return;
             }
 
             if (mMode == PAUSE) {
                 /*
-                 * If the game is merely paused, we should just continue where
-                 * we left off.
+                 * If the game is merely paused, we should just continue where we left off.
                  */
                 setMode(RUNNING);
                 update();
-                return (true);
+                return;
             }
 
             if (mDirection != SOUTH) {
                 mNextDirection = NORTH;
             }
-            return (true);
+            return;
         }
 
-        if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
+        if (direction == Snake.MOVE_DOWN) {
             if (mDirection != NORTH) {
                 mNextDirection = SOUTH;
             }
-            return (true);
+            return;
         }
 
-        if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
+        if (direction == Snake.MOVE_LEFT) {
             if (mDirection != EAST) {
                 mNextDirection = WEST;
             }
-            return (true);
+            return;
         }
 
-        if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
+        if (direction == Snake.MOVE_RIGHT) {
             if (mDirection != WEST) {
                 mNextDirection = EAST;
             }
-            return (true);
+            return;
         }
 
-        return super.onKeyDown(keyCode, msg);
     }
 
     /**
-     * Sets the TextView that will be used to give information (such as "Game
-     * Over" to the user.
+     * Sets the Dependent views that will be used to give information (such as "Game Over" to the
+     * user and also to handle touch events for making movements
      * 
      * @param newView
      */
-    public void setTextView(TextView newView) {
-        mStatusText = newView;
+    public void setDependentViews(TextView msgView, View arrowView, View backgroundView) {
+        mStatusText = msgView;
+        mArrowsView = arrowView;
+        mBackgroundView = backgroundView;
     }
 
     /**
-     * Updates the current mode of the application (RUNNING or PAUSED or the like)
-     * as well as sets the visibility of textview for notification
+     * Updates the current mode of the application (RUNNING or PAUSED or the like) as well as sets
+     * the visibility of textview for notification
      * 
      * @param newMode
      */
@@ -330,23 +330,33 @@
         int oldMode = mMode;
         mMode = newMode;
 
-        if (newMode == RUNNING & oldMode != RUNNING) {
+        if (newMode == RUNNING && oldMode != RUNNING) {
+            // hide the game instructions
             mStatusText.setVisibility(View.INVISIBLE);
             update();
+            // make the background and arrows visible as soon the snake starts moving
+            mArrowsView.setVisibility(View.VISIBLE);
+            mBackgroundView.setVisibility(View.VISIBLE);
             return;
         }
 
         Resources res = getContext().getResources();
         CharSequence str = "";
         if (newMode == PAUSE) {
+            mArrowsView.setVisibility(View.GONE);
+            mBackgroundView.setVisibility(View.GONE);
             str = res.getText(R.string.mode_pause);
         }
         if (newMode == READY) {
+            mArrowsView.setVisibility(View.GONE);
+            mBackgroundView.setVisibility(View.GONE);
+
             str = res.getText(R.string.mode_ready);
         }
         if (newMode == LOSE) {
-            str = res.getString(R.string.mode_lose_prefix) + mScore
-                  + res.getString(R.string.mode_lose_suffix);
+            mArrowsView.setVisibility(View.GONE);
+            mBackgroundView.setVisibility(View.GONE);
+            str = res.getString(R.string.mode_lose, mScore);
         }
 
         mStatusText.setText(str);
@@ -354,11 +364,16 @@
     }
 
     /**
-     * Selects a random location within the garden that is not currently covered
-     * by the snake. Currently _could_ go into an infinite loop if the snake
-     * currently fills the garden, but we'll leave discovery of this prize to a
-     * truly excellent snake-player.
-     * 
+     * @return the Game state as Running, Ready, Paused, Lose
+     */
+    public int getGameState() {
+        return mMode;
+    }
+
+    /**
+     * Selects a random location within the garden that is not currently covered by the snake.
+     * Currently _could_ go into an infinite loop if the snake currently fills the garden, but we'll
+     * leave discovery of this prize to a truly excellent snake-player.
      */
     private void addRandomApple() {
         Coordinate newCoord = null;
@@ -388,10 +403,9 @@
         mAppleList.add(newCoord);
     }
 
-
     /**
-     * Handles the basic update loop, checking to see if we are in the running
-     * state, determining if a move should be made, updating the snake's location.
+     * Handles the basic update loop, checking to see if we are in the running state, determining if
+     * a move should be made, updating the snake's location.
      */
     public void update() {
         if (mMode == RUNNING) {
@@ -411,7 +425,6 @@
 
     /**
      * Draws some walls.
-     * 
      */
     private void updateWalls() {
         for (int x = 0; x < mXTileCount; x++) {
@@ -426,7 +439,6 @@
 
     /**
      * Draws some apples.
-     * 
      */
     private void updateApples() {
         for (Coordinate c : mAppleList) {
@@ -435,38 +447,36 @@
     }
 
     /**
-     * Figure out which way the snake is going, see if he's run into anything (the
-     * walls, himself, or an apple). If he's not going to die, we then add to the
-     * front and subtract from the rear in order to simulate motion. If we want to
-     * grow him, we don't subtract from the rear.
-     * 
+     * Figure out which way the snake is going, see if he's run into anything (the walls, himself,
+     * or an apple). If he's not going to die, we then add to the front and subtract from the rear
+     * in order to simulate motion. If we want to grow him, we don't subtract from the rear.
      */
     private void updateSnake() {
         boolean growSnake = false;
 
-        // grab the snake by the head
+        // Grab the snake by the head
         Coordinate head = mSnakeTrail.get(0);
         Coordinate newHead = new Coordinate(1, 1);
 
         mDirection = mNextDirection;
 
         switch (mDirection) {
-        case EAST: {
-            newHead = new Coordinate(head.x + 1, head.y);
-            break;
-        }
-        case WEST: {
-            newHead = new Coordinate(head.x - 1, head.y);
-            break;
-        }
-        case NORTH: {
-            newHead = new Coordinate(head.x, head.y - 1);
-            break;
-        }
-        case SOUTH: {
-            newHead = new Coordinate(head.x, head.y + 1);
-            break;
-        }
+            case EAST: {
+                newHead = new Coordinate(head.x + 1, head.y);
+                break;
+            }
+            case WEST: {
+                newHead = new Coordinate(head.x - 1, head.y);
+                break;
+            }
+            case NORTH: {
+                newHead = new Coordinate(head.x, head.y - 1);
+                break;
+            }
+            case SOUTH: {
+                newHead = new Coordinate(head.x, head.y + 1);
+                break;
+            }
         }
 
         // Collision detection
@@ -495,7 +505,7 @@
             if (c.equals(newHead)) {
                 mAppleList.remove(c);
                 addRandomApple();
-                
+
                 mScore++;
                 mMoveDelay *= 0.9;
 
@@ -523,10 +533,8 @@
     }
 
     /**
-     * Simple class containing two integer values and a comparison function.
-     * There's probably something I should use instead, but this was quick and
-     * easy to build.
-     * 
+     * Simple class containing two integer values and a comparison function. There's probably
+     * something I should use instead, but this was quick and easy to build.
      */
     private class Coordinate {
         public int x;
@@ -549,5 +557,5 @@
             return "Coordinate: [" + x + "," + y + "]";
         }
     }
-    
+
 }
diff --git a/samples/Snake/src/com/example/android/snake/TileView.java b/samples/Snake/src/com/example/android/snake/TileView.java
old mode 100644
new mode 100755
index a912c53..a25e922
--- a/samples/Snake/src/com/example/android/snake/TileView.java
+++ b/samples/Snake/src/com/example/android/snake/TileView.java
@@ -25,18 +25,16 @@
 import android.util.AttributeSet;
 import android.view.View;
 
-
 /**
- * TileView: a View-variant designed for handling arrays of "icons" or other
- * drawables.
+ * TileView: a View-variant designed for handling arrays of "icons" or other drawables.
  * 
  */
 public class TileView extends View {
 
     /**
-     * Parameters controlling the size of the tiles and their range within view.
-     * Width/Height are in pixels, and Drawables will be scaled to fit to these
-     * dimensions. X/Y Tile Counts are the number of tiles that will be drawn.
+     * Parameters controlling the size of the tiles and their range within view. Width/Height are in
+     * pixels, and Drawables will be scaled to fit to these dimensions. X/Y Tile Counts are the
+     * number of tiles that will be drawn.
      */
 
     protected static int mTileSize;
@@ -47,81 +45,37 @@
     private static int mXOffset;
     private static int mYOffset;
 
-
-    /**
-     * A hash that maps integer handles specified by the subclasser to the
-     * drawable that will be used for that reference
-     */
-    private Bitmap[] mTileArray; 
-
-    /**
-     * A two-dimensional array of integers in which the number represents the
-     * index of the tile that should be drawn at that locations
-     */
-    private int[][] mTileGrid;
-
     private final Paint mPaint = new Paint();
 
-    public TileView(Context context, AttributeSet attrs, int defStyle) {
-        super(context, attrs, defStyle);
+    /**
+     * A hash that maps integer handles specified by the subclasser to the drawable that will be
+     * used for that reference
+     */
+    private Bitmap[] mTileArray;
 
-        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TileView);
-
-        mTileSize = a.getInt(R.styleable.TileView_tileSize, 12);
-        
-        a.recycle();
-    }
+    /**
+     * A two-dimensional array of integers in which the number represents the index of the tile that
+     * should be drawn at that locations
+     */
+    private int[][] mTileGrid;
 
     public TileView(Context context, AttributeSet attrs) {
         super(context, attrs);
 
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TileView);
+        mTileSize = a.getDimensionPixelSize(R.styleable.TileView_tileSize, 12);
 
-        mTileSize = a.getInt(R.styleable.TileView_tileSize, 12);
-        
         a.recycle();
     }
 
-    
-    
-    /**
-     * Rests the internal array of Bitmaps used for drawing tiles, and
-     * sets the maximum index of tiles to be inserted
-     * 
-     * @param tilecount
-     */
-    
-    public void resetTiles(int tilecount) {
-    	mTileArray = new Bitmap[tilecount];
-    }
+    public TileView(Context context, AttributeSet attrs, int defStyle) {
+        super(context, attrs, defStyle);
 
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TileView);
+        mTileSize = a.getDimensionPixelSize(R.styleable.TileView_tileSize, 12);
 
-    @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        mXTileCount = (int) Math.floor(w / mTileSize);
-        mYTileCount = (int) Math.floor(h / mTileSize);
+        a.recycle();
 
-        mXOffset = ((w - (mTileSize * mXTileCount)) / 2);
-        mYOffset = ((h - (mTileSize * mYTileCount)) / 2);
-
-        mTileGrid = new int[mXTileCount][mYTileCount];
-        clearTiles();
-    }
-
-    /**
-     * Function to set the specified Drawable as the tile for a particular
-     * integer key.
-     * 
-     * @param key
-     * @param tile
-     */
-    public void loadTile(int key, Drawable tile) {
-        Bitmap bitmap = Bitmap.createBitmap(mTileSize, mTileSize, Bitmap.Config.ARGB_8888);
-        Canvas canvas = new Canvas(bitmap);
-        tile.setBounds(0, 0, mTileSize, mTileSize);
-        tile.draw(canvas);
-        
-        mTileArray[key] = bitmap;
     }
 
     /**
@@ -137,9 +91,48 @@
     }
 
     /**
-     * Used to indicate that a particular tile (set with loadTile and referenced
-     * by an integer) should be drawn at the given x/y coordinates during the
-     * next invalidate/draw cycle.
+     * Function to set the specified Drawable as the tile for a particular integer key.
+     *
+     * @param key
+     * @param tile
+     */
+    public void loadTile(int key, Drawable tile) {
+        Bitmap bitmap = Bitmap.createBitmap(mTileSize, mTileSize, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(bitmap);
+        tile.setBounds(0, 0, mTileSize, mTileSize);
+        tile.draw(canvas);
+
+        mTileArray[key] = bitmap;
+    }
+
+    @Override
+    public void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+        for (int x = 0; x < mXTileCount; x += 1) {
+            for (int y = 0; y < mYTileCount; y += 1) {
+                if (mTileGrid[x][y] > 0) {
+                    canvas.drawBitmap(mTileArray[mTileGrid[x][y]], mXOffset + x * mTileSize,
+                            mYOffset + y * mTileSize, mPaint);
+                }
+            }
+        }
+
+    }
+
+    /**
+     * Rests the internal array of Bitmaps used for drawing tiles, and sets the maximum index of
+     * tiles to be inserted
+     *
+     * @param tilecount
+     */
+
+    public void resetTiles(int tilecount) {
+        mTileArray = new Bitmap[tilecount];
+    }
+
+    /**
+     * Used to indicate that a particular tile (set with loadTile and referenced by an integer)
+     * should be drawn at the given x/y coordinates during the next invalidate/draw cycle.
      * 
      * @param tileindex
      * @param x
@@ -149,21 +142,16 @@
         mTileGrid[x][y] = tileindex;
     }
 
-
     @Override
-    public void onDraw(Canvas canvas) {
-        super.onDraw(canvas);
-        for (int x = 0; x < mXTileCount; x += 1) {
-            for (int y = 0; y < mYTileCount; y += 1) {
-                if (mTileGrid[x][y] > 0) {
-                    canvas.drawBitmap(mTileArray[mTileGrid[x][y]], 
-                    		mXOffset + x * mTileSize,
-                    		mYOffset + y * mTileSize,
-                    		mPaint);
-                }
-            }
-        }
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        mXTileCount = (int) Math.floor(w / mTileSize);
+        mYTileCount = (int) Math.floor(h / mTileSize);
 
+        mXOffset = ((w - (mTileSize * mXTileCount)) / 2);
+        mYOffset = ((h - (mTileSize * mYTileCount)) / 2);
+
+        mTileGrid = new int[mXTileCount][mYTileCount];
+        clearTiles();
     }
 
 }