Commits

Anonymous committed fb6a276

move to android

Comments (0)

Files changed (24)

android/placeUvote/src/com/placeuvote/android/AddPoll.java

+package com.placeuvote.android;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.Spinner;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.placeuvote.android.R;
+import com.placeuvote.android.PUVDatabase.PollsCursor;
+
+
+/**
+ * AddLocation
+ */
+public class AddPoll extends Activity {
+    private static Button btnAddLocation;
+    private static Spinner spnPoll;
+    private static TextView txtQuestion;
+    private static TextView txtEmail;
+    private PUVDatabase db;
+
+    private class Poll {
+    	public String PollName;
+    	public long id;
+    	Poll( long id, String PollName){
+    		this.id = id;
+    		this.PollName = PollName;
+    	}
+    	@Override
+    	public String toString() {
+    		return this.PollName;
+    	}
+    }
+
+    // Create a button click listener for the AddLocation button.
+    private final Button.OnClickListener btnAddLocationOnClick = new Button.OnClickListener() {
+        public void onClick(View v) {
+        	Poll Poll = (Poll)spnPoll.getSelectedItem();
+//        	Toast.makeText(
+//    			AddLocation.this, 
+//    			String.format(
+//					"Poll: %s (%d)\nTitle: %s\nDesc: %s", 
+//					Poll.PollName, 
+//					Poll.id,
+//					txtTitle.getText(),
+//					txtDescription.getText()
+//				), 
+//    			Toast.LENGTH_SHORT
+//			).show();
+        	if (Poll.id<0 || txtQuestion.getText().length()==0 || txtEmail.getText().length()==0){
+	        	Toast.makeText(AddPoll.this, "Fill out the form completely first.", Toast.LENGTH_LONG).show();
+        	} else {
+	        	db.addPoll(Poll.id, txtQuestion.getText().toString(), txtEmail.getText().toString());
+	        	Toast.makeText(AddPoll.this, "Location added", Toast.LENGTH_SHORT).show();
+	        	//spnPoll.setSelection(0); // select "choose an Poll"
+	        	txtQuestion.setText("");
+	        	txtEmail.setText("");
+        	}
+    	}
+    };
+
+
+    /** Called when the activity is first created. */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        db = new PUVDatabase(this);
+        setContentView(R.layout.addpoll);
+
+        // Find the controls
+        btnAddLocation = (Button) findViewById(R.id.btnAddLocation);
+        spnPoll = (Spinner) findViewById(R.id.spnPoll);
+        txtQuestion = (TextView) findViewById(R.id.txtQuestion);
+        txtEmail = (TextView) findViewById(R.id.txtEmail);
+
+        // btnAddLocation
+        btnAddLocation.setOnClickListener(btnAddLocationOnClick);
+
+        // spnPoll
+        List<Poll> PollsList = new ArrayList<Poll>();
+        PollsList.add(new Poll(-1, "Choose an Poll"));
+        PollsCursor c = db.getPolls(null);
+        for(int i=0; i<c.getCount(); i++){
+        	c.moveToPosition(i);
+        	PollsList.add(new Poll(c.getColPollId(),c.getColQuestion()));
+        }
+        
+        ArrayAdapter<Poll> aspnPolls = new ArrayAdapter<Poll>(
+        		this, android.R.layout.simple_spinner_item, PollsList);
+        aspnPolls.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        spnPoll.setAdapter(aspnPolls);
+    }
+
+    /**
+     * @see android.app.Activity#onResume()
+     */
+    @Override
+    public void onResume() {
+        super.onResume();
+    }
+
+    /**
+     * @param icicle
+     */
+    public void onPause(Bundle icicle) {
+        super.onPause();
+    }
+
+}

android/placeUvote/src/com/placeuvote/android/EditPoll.java

+package com.placeuvote.android;	
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.app.ListActivity;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.Spinner;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.placeuvote.android.R;
+import com.placeuvote.android.PUVDatabase.LocationsCursor;
+import com.placeuvote.android.PUVDatabase.PollsCursor;
+
+
+/**
+ * EditLocation
+ */
+public class EditPoll extends ListActivity {
+    private static Spinner spnPoll;
+    private static TextView txtQuestion;
+    private static TextView txtEmail;
+    private static Integer poll_id;
+    private static Button btnUpdate, btnCancel;
+    private PUVDatabase db;
+    private PollsCursor poll;
+    private LocationsCursor locations;
+    
+    private class Poll {
+    	public String Question;
+    	public long id;
+    	Poll( long id, String Question){
+    		this.id = id;
+    		this.Question = Question;
+    	}
+    	@Override
+    	public String toString() {
+    		return this.Question;
+    	}
+    }
+
+    
+    // Create a button click listener for the Update button.
+    private final Button.OnClickListener btnUpdateOnClick = new Button.OnClickListener() {
+        public void onClick(View v) {
+        	Poll poll = (Poll)spnPoll.getSelectedItem();
+//        	Toast.makeText(
+//        			EditLocation.this, 
+//        			String.format(
+//        					"Location: %d\nPoll: %s (%d)\nTitle: %s\nDesc: %s", 
+//        					poll_id,
+//        					employer.Question, 
+//        					employer.id,
+//        					txtQuestion.getText(),
+//        					txtEmail.getText()
+//        			), 
+//        			Toast.LENGTH_SHORT
+//        	).show();
+        	if (txtQuestion.getText().length()==0 || txtEmail.getText().length()==0){
+	        	Toast.makeText(EditPoll.this, "Fill out the form completely first.", Toast.LENGTH_LONG).show();
+        	} else {
+	        	db.editPoll((long)poll_id, txtQuestion.getText().toString(), txtEmail.getText().toString());
+	        	Toast.makeText(EditPoll.this, "Location updated", Toast.LENGTH_SHORT).show();
+	        	finish();
+        	}
+        }
+    };
+
+    // Create a button click listener for the Cancel button.
+    private final Button.OnClickListener btnCancelOnClick = new Button.OnClickListener() {
+        public void onClick(View v) {
+        		finish();
+        	}
+    };
+
+    /** Called when the activity is first created. */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.editpoll);
+        txtQuestion = (TextView) findViewById(R.id.txtQuestion);
+        spnPoll = (Spinner) findViewById(R.id.spnPoll);
+
+        // get the poll_id for this poll from the bundle passed by MicroLocationsDetail
+        Bundle bIn = this.getIntent().getExtras();
+        poll_id = Integer.valueOf(bIn.getInt("_id"));
+
+        db = new PUVDatabase(this);
+        poll = db.getPollDetails(poll_id.longValue());
+        
+        txtQuestion.setText(poll.getColQuestion());
+
+        btnUpdate = (Button) findViewById(R.id.btnUpdate);
+        btnUpdate.setOnClickListener(btnUpdateOnClick);
+        btnCancel = (Button) findViewById(R.id.btnCancel);
+        btnCancel.setOnClickListener(btnCancelOnClick);
+
+        // spnPoll
+        List<Poll> pollsList = new ArrayList<Poll>();
+        PollsCursor c = db.getPolls(null);
+        int position=0;
+        for(int i=0; i<c.getCount(); i++){
+        	c.moveToPosition(i);
+        	pollsList.add(new Poll(c.getColPollId(),c.getColQuestion()));
+        	if (c.getColPollId()==poll.getColPollId())
+        		position=i;
+        }
+        
+        ArrayAdapter<Poll> aspnPolls = new ArrayAdapter<Poll>(
+        		this, android.R.layout.simple_spinner_item, pollsList);
+        aspnPolls.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        spnPoll.setAdapter(aspnPolls);
+        spnPoll.setSelection(position);
+    }
+}

android/placeUvote/src/com/placeuvote/android/PUVDatabase.java

+package com.placeuvote.android;
+
+import com.placeuvote.android.R;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.SQLException;
+import android.database.sqlite.SQLiteCursor;
+import android.database.sqlite.SQLiteCursorDriver;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.database.sqlite.SQLiteQuery;
+import android.util.Log;
+
+/**
+ * Provides access to the placeUvote locally cached database. 
+ * Note there is a separate synching process to push this data via RSS to and from placeuvote.com
+ * Since this is not a Content Provider, no other applications will have access to the database.
+ */
+public class PUVDatabase extends SQLiteOpenHelper {
+	/** The name of the database file on the file system */
+    private static final String DATABASE_NAME = "PollChoices";
+    /** The version of the database that this class understands. */
+    private static final int DATABASE_VERSION = 1;
+    /** Keep track of context so that we can load SQL from string resources */
+    private final Context mContext;
+
+    /**
+     * Provides self-contained query-specific cursor for Polls.  
+     * The query and all accessor methods are in the class.
+     */
+    public static class PollsCursor extends SQLiteCursor{
+    	/** The query for this cursor */
+    	public static enum SortBy{
+    		Question,
+    		CreatedOn
+    	}
+    	private static final String QUERY = 
+    		"SELECT id, key, question, private, "+
+    		"anonymous, onechoice, locations, dates, "+
+    		"created_on, created_by, last_vote, total_votes, user, email" +
+       		"FROM poll "+
+       		"ORDER BY ";  		
+    		//where _id =";
+    	/** Cursor constructor */
+		private PollsCursor(SQLiteDatabase db, SQLiteCursorDriver driver,
+				String editTable, SQLiteQuery query) {
+			super(db, driver, editTable, query);
+		}
+		/** Private factory class necessary for rawQueryWithFactory() call */
+	    private static class Factory implements SQLiteDatabase.CursorFactory{
+			public Cursor newCursor(SQLiteDatabase db,
+					SQLiteCursorDriver driver, String editTable,
+					SQLiteQuery query) {
+				return new PollsCursor(db, driver, editTable, query);
+			}
+	    }
+	    /* Accessor functions -- one per database column */
+    	public int getColPollId(){return getInt(getColumnIndexOrThrow("_id"));}
+       	public String getColKey(){return getString(getColumnIndexOrThrow("key"));}
+      	public int getColPrivate(){return getInt(getColumnIndexOrThrow("private"));}
+      	public int getColAnonymous(){return getInt(getColumnIndexOrThrow("anonymous"));}
+      	public int getColOneChoice(){return getInt(getColumnIndexOrThrow("onechoice"));}
+      	public int getColLocations(){return getInt(getColumnIndexOrThrow("locations"));}
+      	public long getColDates(){return getLong(getColumnIndexOrThrow("dates"));}
+     	public long getColCreatedOn(){return getLong(getColumnIndexOrThrow("createdon"));}
+     	public String getColCreatedBy(){return getString(getColumnIndexOrThrow("createdby"));}
+     	public long getColLastVote(){return getLong(getColumnIndexOrThrow("lastvote"));}
+     	public int getColTotalVotes(){return getInt(getColumnIndexOrThrow("totalvotes"));}
+     	public String getColUser(){return getString(getColumnIndexOrThrow("user"));}
+     	public String getColEmail(){return getString(getColumnIndexOrThrow("email"));}	
+    	public String getColQuestion(){return getString(getColumnIndexOrThrow("question"));}
+    }
+
+    /**
+     * Provides self-contained query-specific cursor for Location Detail.  
+     * The query and all accessor methods are in the class.
+     */
+    public static class LocationsCursor extends SQLiteCursor{
+    	/** The query for this cursor */
+    	private static final String QUERY = 
+	    "select _id, key, poll_id, choice, loc_lat, loc_long, "+
+        "address, url, votes from choice where poll_id = ";   	
+    	/** Cursor constructor */
+		private LocationsCursor(SQLiteDatabase db, SQLiteCursorDriver driver,
+				String editTable, SQLiteQuery query) {
+			super(db, driver, editTable, query);
+		}
+		/** Private factory class necessary for rawQueryWithFactory() call */
+	    private static class Factory implements SQLiteDatabase.CursorFactory{
+			public Cursor newCursor(SQLiteDatabase db,
+					SQLiteCursorDriver driver, String editTable,
+					SQLiteQuery query) {
+				return new LocationsCursor(db, driver, editTable, query);
+			}
+	    }
+	    /* Accessor functions -- one per database column */
+    	public int getColLocationsId(){return getInt(getColumnIndexOrThrow("_id"));}
+    	public String getColLocationsKey(){return getString(getColumnIndexOrThrow("key"));}
+    	public int getColPollId(){return getInt(getColumnIndexOrThrow("poll_id"));}
+    	public String getColChoice(){return getString(getColumnIndexOrThrow("choice"));}
+    	public long getColLat(){return getLong(getColumnIndexOrThrow("loc_lat"));}
+    	public long getColLong(){return getLong(getColumnIndexOrThrow("loc_long"));}
+    	public String getColAddress(){return getString(getColumnIndexOrThrow("address"));}
+    	public String getColURL(){return getString(getColumnIndexOrThrow("url"));}
+    	public int getColVotes(){return getInt(getColumnIndexOrThrow("votes"));}
+    }
+	
+    public static class DatesCursor extends SQLiteCursor{
+    	private static final String QUERY = 
+  	    "SELECT _id, key, poll_id, datetime, dateortime, votes "+
+	    "where poll_id = ";
+	    private DatesCursor(SQLiteDatabase db, SQLiteCursorDriver driver,
+				String editTable, SQLiteQuery query) {
+			super(db, driver, editTable, query);
+		}
+	    private static class Factory implements SQLiteDatabase.CursorFactory{
+		
+			public Cursor newCursor(SQLiteDatabase db,
+					SQLiteCursorDriver driver, String editTable,
+					SQLiteQuery query) {
+				return new DatesCursor(db, driver, editTable, query);
+			}
+	    }
+    	public int getColDatesId(){return getInt(getColumnIndexOrThrow("_id"));}
+    	public String getColDatesKey(){return getString(getColumnIndexOrThrow("key"));}
+    	public int getColPollId(){return getInt(getColumnIndexOrThrow("poll_id"));}
+    	public long getColDateTime(){return getLong(getColumnIndexOrThrow("datetime"));}
+    	public long getColDateOrTime(){return getLong(getColumnIndexOrThrow("dateortime"));}
+    	public long getColVotes(){return getLong(getColumnIndexOrThrow("votes"));}
+    }
+
+    /**
+     * Provides self-contained query-specific cursor for Polls info.  
+     * The query and all accessor methods are in the class.
+     * Note: for now there is only one record in this table, so this is a lot of 
+     * work to store/retrieve that data.  We do it this way in anticipation of a
+     * day when there would be more than one Polls in the table.
+     */
+    public static class VoterCursor extends SQLiteCursor{
+    	/** The query for this cursor */
+    	private static final String QUERY = 
+    		"SELECT _id, key, poll_id, choice_id, datechoice_id,"+ 
+    		"created_by, created_on"+
+    		"FROM voter ";
+    	/** Cursor constructor */
+		private VoterCursor(SQLiteDatabase db, SQLiteCursorDriver driver,
+				String editTable, SQLiteQuery query) {
+			super(db, driver, editTable, query);
+		}
+		/** Private factory class necessary for rawQueryWithFactory() call */
+	    private static class Factory implements SQLiteDatabase.CursorFactory{
+		
+			public Cursor newCursor(SQLiteDatabase db,
+					SQLiteCursorDriver driver, String editTable,
+					SQLiteQuery query) {
+				return new VoterCursor(db, driver, editTable, query);
+			}
+	    }
+	    /* Accessor functions -- one per database column */
+    	public int getColVoterId(){return getInt(getColumnIndexOrThrow("_id"));}
+    	public String getColVoterKey(){return getString(getColumnIndexOrThrow("key"));}
+    	public int getColPollId(){return getInt(getColumnIndexOrThrow("poll_id"));}
+    	public int getColLoctionsId(){return getInt(getColumnIndexOrThrow("choice_id"));}
+    	public int getColDatesId(){return getInt(getColumnIndexOrThrow("datechoice_id"));}
+     	public String getColCreatedBy(){return getString(getColumnIndexOrThrow("createdby"));}
+     	public long getColCreatedOn(){return getLong(getColumnIndexOrThrow("createdon"));}
+    }
+	
+    /** Constructor */
+    public PUVDatabase(Context context) {
+        super(context, DATABASE_NAME, null, DATABASE_VERSION);
+        this.mContext = context;
+	}
+
+    /**
+     * Execute all of the SQL statements in the String[] array
+     * @param db The database on which to execute the statements
+     * @param sql An array of SQL statements to execute
+     */
+    private void execMultipleSQL(SQLiteDatabase db, String[] sql){
+    	for( String s : sql )
+    		if (s.trim().length()>0)
+    			db.execSQL(s);
+    }
+    
+    /** Called when it is time to create the database */
+	@Override
+	public void onCreate(SQLiteDatabase db) {
+		String[] sql = mContext.getString(R.string.PUVDatabase_onCreate).split("\n");
+		db.beginTransaction();
+		try {
+			// Create tables & test data
+			execMultipleSQL(db, sql);
+			db.setTransactionSuccessful();
+		} catch (SQLException e) {
+            Log.e("Error creating tables and debug data", e.toString());
+        } finally {
+        	db.endTransaction();
+        }
+	}
+	
+	/** Called when the database must be upgraded */
+	@Override
+	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+        Log.w(PUVMap.LOG_TAG, "Upgrading database from version " + oldVersion + " to " +
+                newVersion + ", which will destroy all old data");
+
+		String[] sql = mContext.getString(R.string.PUVDatabase_onUpgrade).split("\n");
+		db.beginTransaction();
+		try {
+			// Create tables & test data
+			execMultipleSQL(db, sql);
+			db.setTransactionSuccessful();
+		} catch (SQLException e) {
+            Log.e("Error creating tables and debug data", e.toString());
+        } finally {
+        	db.endTransaction();
+        }
+
+        // This is cheating.  In the real world, you'll need to add columns, not rebuild from scratch
+        onCreate(db);
+	}
+
+	/**
+	 * Add a new poll to the database.  The poll will have a status of open.
+	 * @param job_id	The employer offering the poll
+	 * @param question			The poll question
+	 * @param email	The poll email
+	 */
+	public void addPoll(long poll_id, String question, String email){
+		ContentValues map = new ContentValues();
+		map.put("question", question);
+		map.put("email", email);
+		try{
+			getWritableDatabase().insert("polls", null, map);
+		} catch (SQLException e) {
+            Log.e("Error writing new poll", e.toString());
+		}
+	}
+
+	/**
+	 * Update a poll in the database.
+	 * @param poll_id	The poll id of the existing poll
+	 * @param question	The poll question
+	 * @param email	The poll creators email
+	 */
+	public void editPoll(long poll_id, String question, String email) {
+		ContentValues map = new ContentValues();
+		map.put("question", question);
+		map.put("email", email);
+		String[] whereArgs = new String[]{Long.toString(poll_id)};
+		try{
+			getWritableDatabase().update("polls", map, "_id=?", whereArgs);
+		} catch (SQLException e) {
+            Log.e("Error updating existing poll", e.toString());
+		}
+	}
+
+	/**
+	 * Delete a location from the database.
+	 * @param location_id		The location_id of the choice to delete
+	 */
+	public void deleteLocation(long location_id) {
+		String[] whereArgs = new String[]{Long.toString(location_id)};
+		try{
+			getWritableDatabase().delete("choice", "_id=?", whereArgs);
+		} catch (SQLException e) {
+            Log.e("Error deleteing location", e.toString());
+		}
+	}
+
+	/** Returns the number of Locations */
+	public int getLocationsCount(long pollId){
+
+		Cursor c = null;
+        try {
+            c = getReadableDatabase().rawQuery("SELECT count(*) FROM choice where poll_id =" + pollId, null);
+            if (0 >= c.getCount()) { return 0; }
+            c.moveToFirst();
+            return c.getInt(0);
+        }
+        finally {
+            if (null != c) {
+                try { c.close(); }
+                catch (SQLException e) { }
+            }
+        }
+	}
+
+	/** Returns a PollsCursor for a Poll
+     */
+    public PollsCursor getPollDetails(long pollId) {
+    	SQLiteDatabase d = getReadableDatabase();
+    	PollsCursor c = (PollsCursor) d.rawQueryWithFactory(
+			new PollsCursor.Factory(),
+	    	PollsCursor.QUERY + pollId,
+			null,
+			null);
+    	c.moveToFirst();
+        return c;
+    }
+	
+    /** Returns a PollsCursor for all Polls
+     */
+    public PollsCursor getPolls(PollsCursor.SortBy sortBy) {
+    	SQLiteDatabase d = getReadableDatabase();
+    	PollsCursor c = (PollsCursor) d.rawQueryWithFactory(
+			new PollsCursor.Factory(),
+	    	PollsCursor.QUERY + sortBy.toString(),
+			null,
+			null);
+    	c.moveToFirst();
+        return c;
+    }
+
+    /** Returns a sorted DatesCursor for the specified pollId
+     * @param pollId The _id of the poll
+     */
+    public DatesCursor getDates(long pollId) {
+    	String sql = DatesCursor.QUERY + pollId + " order by datetime";
+    	SQLiteDatabase d = getReadableDatabase();
+    	DatesCursor c = (DatesCursor) d.rawQueryWithFactory(
+			new DatesCursor.Factory(),
+			sql,
+			null,
+			null);
+    	c.moveToFirst();
+        return c;
+    }
+
+    /** Return a LocationsCursor
+     * @param sortBy the sort criteria
+     */
+    public LocationsCursor getLocations(long pollId) {
+    	String sql = LocationsCursor.QUERY + pollId;
+    	SQLiteDatabase d = getReadableDatabase();
+        LocationsCursor c = (LocationsCursor) d.rawQueryWithFactory(
+        	new LocationsCursor.Factory(),
+        	sql,
+        	null,
+        	null);
+        c.moveToFirst();
+        return c;
+    }
+    /** Returns the VoterCursor
+     * 
+     */
+    public VoterCursor getVoter(long pollId) {
+    	String sql = VoterCursor.QUERY + pollId;
+    	SQLiteDatabase d = getReadableDatabase();
+    	VoterCursor c = (VoterCursor) d.rawQueryWithFactory(
+			new VoterCursor.Factory(),
+			sql,
+			null,
+			null);
+    	c.moveToFirst();
+        return c;
+    }
+
+}

android/placeUvote/src/com/placeuvote/android/PUVMap.java

+package com.placeuvote.android;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.location.Location;
+import android.location.LocationManager;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.Spinner;
+import android.widget.TextView;
+import android.widget.AdapterView.OnItemSelectedListener;
+
+import com.google.android.maps.GeoPoint;
+import com.google.android.maps.ItemizedOverlay;
+import com.google.android.maps.MapActivity;
+import com.google.android.maps.MapController;
+import com.google.android.maps.MapView;
+import com.google.android.maps.MyLocationOverlay;
+import com.google.android.maps.OverlayItem;
+import com.placeuvote.android.R;
+import com.placeuvote.android.PUVDatabase.LocationsCursor;
+import com.placeuvote.android.PUVDatabase.PollsCursor;
+/**
+ * Poll Locations
+ */
+public class PUVMap extends MapActivity {
+    /**
+     * Application-wide log tag
+     */
+	static final String LOG_TAG = "placeUvote";
+
+	/** 
+	 * Database cursor to access user information
+	 */
+	private LocationsCursor Locations;
+	private Long poll_id;
+    /**
+     * LocationsOverlay
+     */
+    private class PUVOverlay extends ItemizedOverlay<OverlayItem> {
+
+        /**
+         * @param marker the push-pin
+         */
+        public PUVOverlay(Drawable marker) {
+            super(marker);
+            populate();
+        }
+
+        /**
+         * @see com.google.android.maps.ItemizedOverlay#size()
+         */
+        @Override
+        public int size() {
+        	int size = db.getLocationsCount(poll_id);
+        	return size;
+        }
+
+        /**
+         * @see com.google.android.maps.ItemizedOverlay#createItem(int)
+         */
+        @Override
+        protected OverlayItem createItem(int i) {
+        	LocationsCursor c = db.getLocations(i+1);
+        	String contactName = c.getColChoice();
+        	String description = c.getColAddress();
+        	int lat = (int) c.getColLat();
+        	int lon = (int) c.getColLong();
+        	return new OverlayItem(new GeoPoint(lat, lon), contactName, description);
+        }
+
+        /**
+         * React to tap events on Map by showing an appropriate detail activity
+         *
+         * @see com.google.android.maps.ItemizedOverlay#onTap(com.google.android.maps.GeoPoint, com.google.android.maps.MapView)
+         */
+        @Override
+        public boolean onTap(GeoPoint p, MapView mvMap1) {
+            long lat = p.getLatitudeE6();
+            long lon = p.getLongitudeE6();
+          
+            long rowid = -1;
+            LocationsCursor c = db.getLocations(poll_id); //LocationsCursor.SortBy.title
+            for( int i=0; i<c.getCount(); i++){
+            	if (Math.abs(c.getColLat()-lat)<1000 && Math.abs(c.getColLong()-lon)<1000){
+            		rowid = c.getColLocationsId();
+            		break;
+            	} else {
+            		c.moveToNext();
+            	}
+            }
+            
+            if (0 > rowid) { return false; }
+            
+            Bundle b = new Bundle();
+            b.putLong("_id", rowid);
+            Intent i = new Intent(PUVMap.this, PollDetail.class);
+            i.putExtras(b);
+            startActivity(i);
+
+            return true;
+        }
+    }
+
+
+    MapView mvMap;
+    PUVDatabase db;
+    MyLocationOverlay mMyLocationOverlay;
+    int latitude, longitude;
+
+    /**
+     * Called when the activity is first created.
+     *
+     * @see com.google.android.maps.MapActivity#onCreate(android.os.Bundle)
+     */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.main);
+
+        db = new PUVDatabase(this);
+
+        // Get current position
+        final Location myLocation
+            = getCurrentLocation((LocationManager) getSystemService(Context.LOCATION_SERVICE));
+
+        Spinner spnLocations = (Spinner) findViewById(R.id.spnLocations);
+        mvMap = (MapView) findViewById(R.id.mapmain);
+
+        // get the map controller
+        final MapController mc = mvMap.getController();
+
+        mMyLocationOverlay = new MyLocationOverlay(this, mvMap);
+        mMyLocationOverlay.enableMyLocation();
+        mMyLocationOverlay.runOnFirstFix(
+            new Runnable() {
+                public void run() {
+                    mc.animateTo(mMyLocationOverlay.getMyLocation());
+                    mc.setZoom(16);
+                }
+            });
+
+        Drawable marker = getResources().getDrawable(R.drawable.marker_image);
+        marker.setBounds(0, 0, marker.getIntrinsicWidth(), marker.getIntrinsicHeight());
+        mvMap.getOverlays().add(new PUVOverlay(marker));
+
+        mvMap.setClickable(true);
+        mvMap.setEnabled(true);
+        mvMap.setSatellite(false);
+        mvMap.setTraffic(false);
+        mvMap.setStreetView(false);
+        
+        // start out with a general zoom
+        mc.setZoom(16);
+        mvMap.invalidate();
+
+        // Create a button click listener for the List Locations button.
+        Button btnList = (Button) findViewById(R.id.btnShowList);
+        btnList.setOnClickListener(new Button.OnClickListener() {
+            public void onClick(View v) {
+                Intent intent = new Intent(PUVMap.this.getApplication(), PollList.class);
+                startActivity(intent);
+            }
+        });
+
+        // Load a HashMap with locations and positions
+        List<String> lsLocations = new ArrayList<String>();
+        final HashMap<String, GeoPoint> hmLocations = new HashMap<String, GeoPoint>();
+        hmLocations.put("Current Location", new GeoPoint(latitude, longitude));
+        lsLocations.add("Current Location");
+
+        // Add favorite locations from this user's record in Polls table
+        Locations = db.getLocations(poll_id);
+        for( int rowNum=0; rowNum<Locations.getCount(); rowNum++){
+        	Locations.moveToPosition(rowNum);
+         	hmLocations.put(Locations.getColAddress(), new GeoPoint((int)Locations.getColLat(), (int)Locations.getColLong()));
+            lsLocations.add(Locations.getColChoice());
+        }
+        
+        ArrayAdapter<String> aspnLocations
+            = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, lsLocations);
+        aspnLocations.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+        spnLocations.setAdapter(aspnLocations);
+
+        // Setup a callback for the spinner
+        spnLocations.setOnItemSelectedListener(
+            new OnItemSelectedListener() {
+                public void onNothingSelected(AdapterView<?> arg0) { }
+
+                public void onItemSelected(AdapterView<?> parent, View v, int position, long id)  {
+                    TextView vt = (TextView) v;
+                    if ("Current Location".equals(vt.getText())) {
+                    	mMyLocationOverlay.enableMyLocation();
+                    	try {
+                    		mc.animateTo(mMyLocationOverlay.getMyLocation());
+                    	}
+                    	catch (Exception e) {
+                    		Log.i("MicroLocations", "Unable to animate map", e);
+                    	}
+                    	mvMap.invalidate();
+                    } else {
+                    	mMyLocationOverlay.disableMyLocation();
+                        mc.animateTo(hmLocations.get(vt.getText()));
+                    }
+                    mvMap.invalidate();
+                }
+            });
+    }
+
+    protected GeoPoint setCurrentGeoPoint(){
+    	return mMyLocationOverlay.getMyLocation();
+    }
+    
+    /**
+     * @see com.google.android.maps.MapActivity#onPause()
+     */
+    @Override
+    public void onPause() {
+        super.onPause();
+        mMyLocationOverlay.disableMyLocation();
+    }
+
+    // stop tracing when application ends
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+    }
+
+    /**
+     * @see com.google.android.maps.MapActivity#onResume()
+     */
+    @Override
+    public void onResume() {
+        super.onResume();
+        mMyLocationOverlay.enableMyLocation();
+    }
+
+    /**
+     * Setup menus for this page
+     *
+     * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
+     */
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        boolean supRetVal = super.onCreateOptionsMenu(menu);
+        menu.add(Menu.NONE, 0, Menu.NONE, getString(R.string.map_menu_zoom_in));
+        menu.add(Menu.NONE, 1, Menu.NONE, getString(R.string.map_menu_zoom_out));
+        menu.add(Menu.NONE, 2, Menu.NONE, getString(R.string.map_menu_set_satellite));
+        menu.add(Menu.NONE, 3, Menu.NONE, getString(R.string.map_menu_set_map));
+        menu.add(Menu.NONE, 4, Menu.NONE, getString(R.string.map_menu_set_traffic));
+        menu.add(Menu.NONE, 5, Menu.NONE, getString(R.string.map_menu_show_list));
+        return supRetVal;
+    }
+
+    /**
+     * @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
+     */
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case 0:
+                // Zoom in
+                zoomIn();
+                return true;
+            case 1:
+                // Zoom out
+                zoomOut();
+                return true;
+            case 2:
+                // Toggle satellite views
+                mvMap.setSatellite(!mvMap.isSatellite());
+                return true;
+            case 3:
+                // Toggle street views
+                mvMap.setStreetView(!mvMap.isStreetView());
+                return true;
+            case 4:
+                // Toggle traffic views
+                mvMap.setTraffic(!mvMap.isTraffic());
+                return true;
+            case 5:
+                // Show the job list activity
+                startActivity(new Intent(PUVMap.this, PollList.class));
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * @see android.app.Activity#onKeyDown(int, android.view.KeyEvent)
+     */
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        switch (keyCode) {
+            case KeyEvent.KEYCODE_DPAD_UP: // zoom in
+                zoomIn();
+                return true;
+            case KeyEvent.KEYCODE_DPAD_DOWN: // zoom out
+                zoomOut();
+                return true;
+            case KeyEvent.KEYCODE_BACK: // go back (meaning exit the app)
+                finish();
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * Required method to indicate whether we display routes
+     */
+    @Override
+    protected boolean isRouteDisplayed() { return false; }
+
+    /**
+     * Zoom in on the map
+     */
+    private void zoomIn() {
+        mvMap.getController().setZoom(mvMap.getZoomLevel() + 1);
+    }
+
+    /**
+     * Zoom out on the map, but not past level 10
+     */
+    private void zoomOut() {
+        int zoom = mvMap.getZoomLevel() - 1;
+        if (zoom < 5) { zoom = 5; }
+        mvMap.getController().setZoom(zoom);
+    }
+
+    /**
+     * @return the current location
+     */
+    private Location getCurrentLocation(LocationManager lm) {
+         Location l = lm.getLastKnownLocation("gps");
+        if (null != l) { return l; }
+
+        // getLastKnownLocation returns null if loc provider is not enabled
+        l = new Location("gps");
+        l.setLatitude(42.352299);
+        l.setLatitude(-71.063979);
+
+        return l;
+    }
+
+}

android/placeUvote/src/com/placeuvote/android/PollDetail.java

+package com.placeuvote.android;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ImageButton;
+import android.widget.TextView;
+import android.widget.CheckBox;
+
+import com.placeuvote.android.R;
+import com.placeuvote.android.PUVDatabase.PollsCursor;
+
+
+/**
+ * PollDetail
+ */
+public class PollDetail extends Activity {
+    private static Integer poll_id;
+    private static TextView txtKey;
+    private static CheckBox chkPrivate;
+    private static CheckBox chkAnonymous;
+    private static CheckBox chkOneChoice;
+    private static TextView numLocations;
+    private static TextView numDates;
+    private static TextView dateCreatedOn;
+    private static TextView txtCreatedBy;
+    private static TextView dateLastVote;
+    private static TextView numTotalVotes;
+    private static TextView txtUser;
+    private static TextView txtEmail;
+    private static TextView txtQuestion;
+    
+    PUVDatabase db;
+
+    private PollsCursor poll;
+    /**
+    final CheckBox chkPrivate = (CheckBox) findViewById(R.id.chkPrivate);
+    chkPrivate.setOnClickListener(new OnClickListener() {
+	    public void onClick(View v) {
+		// Perform action on clicks, depending on whether it's now checked
+		if (((CheckBox) v).isChecked()) {
+		    Toast.makeText(HelloFormStuff.this, "Selected", Toast.LENGTH_SHORT).show();
+		} else {
+		    Toast.makeText(HelloFormStuff.this, "Not selected", Toast.LENGTH_SHORT).show();
+		}
+	    }
+	});
+    */
+	public boolean IntToBool(int intValue)
+	{
+	    return (intValue != 0);
+	}
+    
+    /**
+     * Called when the activity is first created.
+     *
+     * @see android.app.Activity#onCreate(android.os.Bundle)
+     */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+/** Edit res/layout/polldetail.xml to match these form elements
+ *  - txtEmail, txtUser, numLocations and numDates not displayed */
+        setContentView(R.layout.polldetail);
+        txtKey = (TextView) findViewById(R.id.txtKey);
+        chkPrivate = (CheckBox) findViewById(R.id.chkPrivate);
+        chkAnonymous = (CheckBox) findViewById(R.id.chkAnonymous);
+        chkOneChoice = (CheckBox) findViewById(R.id.chkOneChoice);
+        dateCreatedOn = (TextView) findViewById(R.id.dateCreatedOn);
+        txtCreatedBy = (TextView) findViewById(R.id.txtCreatedBy);
+        dateLastVote = (TextView) findViewById(R.id.dateLastVote);
+        numTotalVotes = (TextView) findViewById(R.id.numTotalVotes);
+        txtQuestion = (TextView) findViewById(R.id.txtQuestion);
+
+        // get the poll_id for this poll from the bundle passed by PollList
+        Bundle bIn = this.getIntent().getExtras();
+        poll_id = Integer.valueOf(bIn.getInt("_id"));
+
+        db = new PUVDatabase(this);
+        poll = db.getPollDetails(poll_id.longValue());
+
+		java.text.DateFormat dateFormat = android.text.format.DateFormat.getDateFormat(getApplicationContext());
+	        // fill in the form and display
+		txtKey.setText(poll.getColKey());
+		chkPrivate.setChecked(IntToBool(poll.getColPrivate()));
+		chkAnonymous.setChecked(IntToBool(poll.getColAnonymous()));
+		chkOneChoice.setChecked(IntToBool(poll.getColOneChoice()));
+		dateCreatedOn.setText("Created: " + dateFormat.format(poll.getColCreatedOn()));
+		txtCreatedBy.setText(poll.getColCreatedBy());
+		dateLastVote.setText("Last vote: " + dateFormat.format(poll.getColLastVote()));
+		numTotalVotes.setText(poll.getColTotalVotes());
+        txtUser.setText(poll.getColUser());
+        txtQuestion.setText(poll.getColQuestion());
+
+    }
+
+    /**
+     * Setup menus for this page.
+     *
+     * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
+     */
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        boolean supRetVal = super.onCreateOptionsMenu(menu);
+        menu.add(0, 0, Menu.NONE, getString(R.string.detail_menu_back_to_list));
+        menu.add(0, 1, Menu.NONE, getString(R.string.detail_menu_poll_info));
+        menu.add(0, 2, Menu.NONE, getString(R.string.detail_menu_delete_location));
+        menu.add(0, 3, Menu.NONE, getString(R.string.detail_menu_edit_location));
+        return supRetVal;
+    }
+
+    /**
+     * @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
+     */
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case 0:
+                // Go back to the list page
+                finish();
+                return true;
+            case 1:
+                // Go to the employer detail page
+                Intent iEmp = new Intent(PollDetail.this, VoterDetail.class);
+                Bundle bEmp = new Bundle();
+                bEmp.putInt("_id", poll_id.intValue());
+                iEmp.putExtras(bEmp);
+
+                startActivity(iEmp);
+                return true;
+            case 2:
+            	// Delete this job
+                // Setup Delete Alert Dialog
+            	final int DELETE_JOB = 0;
+            	final int CANCEL_DELETE = 1;
+            	
+                Handler mHandler = new Handler() {    	
+                    public void handleMessage(Message msg) {
+                        switch (msg.what) {
+                            case DELETE_JOB:
+                            db.deleteLocation(poll_id);
+                            startActivity(new Intent(PollDetail.this, PollList.class));
+                            break;
+                    
+                            case CANCEL_DELETE:
+                            // Do nothing
+                            break;
+                        }
+                    }
+                };
+                // "Answer" callback.
+                final Message acceptMsg = Message.obtain();
+                acceptMsg.setTarget(mHandler);
+                acceptMsg.what = DELETE_JOB;
+                    
+                // "Cancel" callback.
+                final Message rejectMsg = Message.obtain();
+                rejectMsg.setTarget(mHandler);
+                rejectMsg.what = CANCEL_DELETE;
+
+                new AlertDialog.Builder(this)
+                  .setMessage("Are you sure you want to delete this poll?")
+                  .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
+                	  public void onClick(DialogInterface dialog, int value) {
+                		  rejectMsg.sendToTarget();
+                	  }})
+                  .setPositiveButton("Delete", new DialogInterface.OnClickListener() {
+                	  public void onClick(DialogInterface dialog, int value) {
+                    		  acceptMsg.sendToTarget();
+                	  }})
+                  .setOnCancelListener(new DialogInterface.OnCancelListener() {
+                        public void onCancel(DialogInterface dialog) {
+                          rejectMsg.sendToTarget();
+                      }})
+                      .show();    
+            	return true;
+            case 3:
+            	// Edit this job
+            	// Start the Edit Location Activity, passing this poll's id
+                Intent iEdit = new Intent(PollDetail.this, EditPoll.class);
+                Bundle bEdit = new Bundle();
+                bEdit.putInt("_id", poll_id);
+                iEdit.putExtras(bEdit);
+                startActivity(iEdit);            	
+            	return true;
+            	
+            default:
+                return false;
+        }
+    }
+}

android/placeUvote/src/com/placeuvote/android/PollList.java

+package com.placeuvote.android;
+
+import java.util.ArrayList;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.Button;
+import android.widget.Spinner;
+import android.widget.TableLayout;
+import android.widget.TableRow;
+import android.widget.TableLayout.LayoutParams;
+
+import com.placeuvote.android.R;
+import com.placeuvote.android.PUVDatabase.LocationsCursor;
+import com.placeuvote.android.PUVDatabase.PollsCursor;
+/**
+ * PollsList
+ */
+public class PollList extends Activity {
+	
+    private static class puvButton extends Button {
+        protected int jrow; // puvButton is just a button that knows which poll number it's associated with
+
+        public puvButton(Context btnContext) {
+            super(btnContext);
+        }
+    }
+
+    private static Button btnQuestion;
+    private static Button btnView;
+    private static Button btnVote;
+    private static Button btnCreate;
+    private static Spinner spnPoll;
+    static TableLayout tblPolls;
+
+    
+
+    // Create a button click listener for the Question buttons in the list
+    // Clicking on any of these should take us to a detail listing for that
+    // job
+    private final Button.OnClickListener btnViewClick = new Button.OnClickListener() {
+        public void onClick(View v) {
+            Intent i = new Intent(PollList.this, PollDetail.class);
+            Bundle b = new Bundle();
+            puvButton vb = (puvButton) v;
+            cursor.moveToPosition(vb.jrow);
+            b.putInt("_id", (int) cursor.getColPollId());
+            i.putExtras(b);
+
+            startActivity(i);
+        }
+    };
+
+    private PollsCursor cursor;
+    private PUVDatabase db;
+
+    ArrayList<View> lstTable;
+
+    /** Called when the activity is first created. */
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.polllist);
+
+        btnView = (Button) findViewById(R.id.btnView);
+        btnView.setOnClickListener(btnViewClick);
+        spnPoll = (Spinner) findViewById(R.id.spnPolls);
+        spnPoll.setTag("Poll");
+        
+        db = new PUVDatabase(this);
+        
+        fillData(PollsCursor.SortBy.CreatedOn);
+    }
+
+    /**
+     * @see android.app.Activity#onResume()
+     */
+    @Override
+    public void onResume() {
+        super.onResume();
+    }
+
+    /**
+     * @param icicle
+     */
+    public void onPause(Bundle icicle) {
+        super.onPause();
+    }
+
+    /**
+     * Make sure to stop the animation when we're no longer on screen, failing 	public int getColVoterId(){return getInt(getColumnIndexOrThrow("_id"));}
+    	public String getColVoterKey(){return getString(getColumnIndexOrThrow("key"));}
+    	public int getColPollsId(){return getInt(getColumnIndexOrThrow("poll_id"));}
+    	public int getColLoctionsId(){return getInt(getColumnIndexOrThrow("choice_id"));}
+    	public int getColDatesId(){return getInt(getColumnIndexOrThrow("datechoice_id"));}
+     	public String getColCreatedBy(){return getString(getColumnIndexOrThrow("createdby"));}
+     	public long getColCreattedOn(){return getLong(getColumnIndexOrThrow("createdon"));}
+     * to do so will cause a lot of unnecessary cpu-usage!
+     */
+    @Override
+    public void onSaveInstanceState(Bundle icicle) {
+        super.onSaveInstanceState(icicle);
+    }
+
+    /**
+     * Setup menus for this page
+     * 
+     * @see android.app.Activity#onCreateOptionsMenu(android.view.Menu)
+     */
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+        boolean supRetVal = super.onCreateOptionsMenu(menu);
+        menu.add(0, 0, Menu.NONE, getString(R.string.list_menu_back_to_map));
+        menu .add(0, 1, Menu.NONE, getString(R.string.list_menu_sort_by_poll));
+        menu.add(0, 2, Menu.NONE, getString(R.string.list_menu_add_dates));
+        menu.add(0, 3, Menu.NONE, getString(R.string.list_menu_add_location));
+        return supRetVal;
+    }
+
+
+    /**Poll
+     * @see android.app.Activity#onOptionsItemSelected(android.view.MenuItem)
+     */
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case 0:
+                // Go back to the map page
+                finish();
+                return true;
+            case 1:
+                // Sort the list by poll Question
+                for (View vw : lstTable) {
+                    tblPolls.removeView(vw);
+                }
+                fillData(PollsCursor.SortBy.Question);
+                return true;
+            case 2:
+                // Sort the list by poll creation date
+                for (View vw : lstTable) {
+                    tblPolls.removeView(vw);
+                }
+                fillData(PollsCursor.SortBy.CreatedOn);
+                return true;
+            case 3:
+            	// Add a new location
+                Intent i = new Intent(PollList.this, AddPoll.class);
+                startActivity(i);
+                 	return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * @param sortBy
+     */
+    void fillData(PollsCursor.SortBy sortBy) {
+        // Create a new list to track the addition of TextViews
+        lstTable = new ArrayList<View>(); // a list of the TableRow's added
+        // Get all of the rows from the database and create the table
+        // Keep track of the TextViews added in list lstTable
+        cursor = db.getPolls(sortBy);
+        // Create a table row that contains two lists
+        // (one for job Questions, one for employers)
+        // Now load the lists with job Question and employer name
+        //for (Locations row : rows) {
+        for( int rowNum=0; rowNum<cursor.getCount(); rowNum++){
+        	cursor.moveToPosition(rowNum);
+            TableRow tr = new TableRow(this);
+            tr.setLayoutParams(new LayoutParams(
+                android.view.ViewGroup.LayoutParams.FILL_PARENT,
+                android.view.ViewGroup.LayoutParams.WRAP_CONTENT));
+            // Create a Button for the job Question.
+            puvButton btn1 = new puvButton(this);
+            // Button btn1 = new Button(this);
+            btn1.jrow = rowNum;
+            btn1.setText(cursor.getColQuestion());
+            btn1.setPadding(1, 0, 3, 0);
+            btn1.setHeight(40);
+            btn1.setGravity(android.view.Gravity.CENTER);
+            // btn1.setBackgroundColor(colorByStatus((int) cursor.getColStatus()));
+            btn1.setOnClickListener(btnViewClick);
+            // Add poll Question to poll list.
+            tr.addView(btn1);
+
+            Button btn2 = new Button(this);
+            btn2.setPadding(1, 0, 3, 0);
+            btn2.setText(cursor.getColQuestion());
+            btn2.setHeight(40);
+            btn2.setGravity(android.view.Gravity.CENTER);
+            btn2.setBackgroundColor(Color.WHITE);
+            /* Add employer name to that list. */
+            tr.addView(btn2);
+
+            tblPolls.addView(tr);
+            // lstLocations.add(btn1.getId()); // keep job id to get more info later if needed
+            lstTable.add(tr); // keep track of the rows we've added (to remove later)
+        }
+    }
+
+    // Set a background color based on the current status of a job
+    private int colorByStatus(int status) {
+        switch (status) {
+            case 1: // Position is taken
+                return Color.argb(150, 255, 0, 0); // red
+            case 2: // There are applicants for the position
+                return Color.argb(150, 44, 211, 207); // yellow
+            case 3: // The position is available
+                return Color.argb(150, 0, 255, 0); // green
+            default:
+                return Color.WHITE;
+        }
+    }
+}

android/placeUvote/src/com/placeuvote/android/RSSFeed.java

+package com.placeuvote.android;
+
+
+import java.util.List;
+import java.util.Vector;
+
+import com.placeuvote.android.RSSItem;
+
+public class RSSFeed 
+{
+	private String _title = null;
+	private String _pubdate = null;
+	private int _itemcount = 0;
+	private List<RSSItem> _itemlist;
+	
+	
+	RSSFeed()
+	{
+		_itemlist = new Vector(0); 
+	}
+	int addItem(RSSItem item)
+	{
+		_itemlist.add(item);
+		_itemcount++;
+		return _itemcount;
+	}
+	RSSItem getItem(int location)
+	{
+		return _itemlist.get(location);
+	}
+	List getAllItems()
+	{
+		return _itemlist;
+	}
+	int getItemCount()
+	{
+		return _itemcount;
+	}
+	void setTitle(String title)
+	{
+		_title = title;
+	}
+	void setPubDate(String pubdate)
+	{
+		_pubdate = pubdate;
+	}
+	String getTitle()
+	{
+		return _title;
+	}
+	String getPubDate()
+	{
+		return _pubdate;
+	}
+	
+	
+}

android/placeUvote/src/com/placeuvote/android/RSSHandler.java

+package com.placeuvote.android;
+
+import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.*;
+import android.util.Log;
+
+
+
+public class RSSHandler extends DefaultHandler 
+{
+	
+	RSSFeed _feed;
+	RSSItem _item;
+	String _lastElementName = "";
+	boolean bFoundChannel = false;
+	final int RSS_TITLE = 1;
+	final int RSS_LINK = 2;
+	final int RSS_DESCRIPTION = 3;
+	final int RSS_CATEGORY = 4;
+	final int RSS_PUBDATE = 5;
+	
+	int depth = 0;
+	int currentstate = 0;
+	/*
+	 * Constructor 
+	 */
+	RSSHandler()
+	{
+	}
+	
+	/*
+	 * getFeed - this returns our feed when all of the parsing is complete
+	 */
+	RSSFeed getFeed()
+	{
+		return _feed;
+	}
+	
+	
+	public void startDocument() throws SAXException
+	{
+		// initialize our RSSFeed object - this will hold our parsed contents
+		_feed = new RSSFeed();
+		// initialize the RSSItem object - we will use this as a crutch to grab the info from the channel
+		// because the channel and items have very similar entries..
+		_item = new RSSItem();
+
+	}
+	public void endDocument() throws SAXException
+	{
+	}
+	public void startElement(String namespaceURI, String localName,String qName, Attributes atts) throws SAXException
+	{
+		depth++;
+		if (localName.equals("channel"))
+		{
+			currentstate = 0;
+			return;
+		}
+		if (localName.equals("image"))
+		{
+			// record our feed data - we temporarily stored it in the item :)
+			_feed.setTitle(_item.getTitle());
+			_feed.setPubDate(_item.getPubDate());
+		}
+		if (localName.equals("item"))
+		{
+			// create a new item
+			_item = new RSSItem();
+			return;
+		}
+		if (localName.equals("title"))
+		{
+			currentstate = RSS_TITLE;
+			return;
+		}
+		if (localName.equals("description"))
+		{
+			currentstate = RSS_DESCRIPTION;
+			return;
+		}
+		if (localName.equals("link"))
+		{
+			currentstate = RSS_LINK;
+			return;
+		}
+		if (localName.equals("category"))
+		{
+			currentstate = RSS_CATEGORY;
+			return;
+		}
+		if (localName.equals("pubDate"))
+		{
+			currentstate = RSS_PUBDATE;
+			return;
+		}
+		// if we don't explicitly handle the elementstartSubActivity, make sure we don't wind up erroneously 
+		// storing a newline or other bogus data into one of our existing elements
+		currentstate = 0;
+	}
+	
+	public void endElement(String namespaceURI, String localName, String qName) throws SAXException
+	{
+		depth--;
+		if (localName.equals("item"))
+		{
+			// add our item to the list!
+			_feed.addItem(_item);
+			return;
+		}
+	}
+	 
+	public void characters(char ch[], int start, int length)
+	{
+		String theString = new String(ch,start,length);
+		Log.i("RSSReader","characters[" + theString + "]");
+		
+		switch (currentstate)
+		{
+			case RSS_TITLE:
+				_item.setTitle(theString);
+				currentstate = 0;
+				break;
+			case RSS_LINK:
+				_item.setLink(theString);
+				currentstate = 0;
+				break;
+			case RSS_DESCRIPTION:
+				_item.setDescription(theString);
+				currentstate = 0;
+				break;
+			case RSS_CATEGORY:
+				_item.setCategory(theString);
+				currentstate = 0;
+				break;
+			case RSS_PUBDATE:
+				_item.setPubDate(theString);
+				currentstate = 0;
+				break;
+			default:
+				return;
+		}
+		
+	}
+}

android/placeUvote/src/com/placeuvote/android/RSSItem.java

+package com.placeuvote.android;
+
+public class RSSItem 
+{
+	private String _title = null;
+	private String _description = null;
+	private String _link = null;
+	private String _category = null;
+	private String _pubdate = null;
+
+	
+	RSSItem()
+	{
+	}
+	void setTitle(String title)
+	{
+		_title = title;
+	}
+	void setDescription(String description)
+	{
+		_description = description;
+	}
+	void setLink(String link)
+	{
+		_link = link;
+	}
+	void setCategory(String category)
+	{
+		_category = category;
+	}
+	void setPubDate(String pubdate)
+	{
+		_pubdate = pubdate;
+	}
+	String getTitle()
+	{
+		return _title;
+	}
+	String getDescription()
+	{
+		return _description;
+	}
+	String getLink()
+	{
+		return _link;
+	}
+	String getCategory()
+	{
+		return _category;
+	}
+	String getPubDate()
+	{
+		return _pubdate;
+	}
+	public String toString()
+	{
+		// limit how much text we display
+		if (_title.length() > 42)
+		{
+			return _title.substring(0, 42) + "...";
+		}
+		return _title;
+	}
+}

android/placeUvote/src/com/placeuvote/android/RSSReader.java

+package com.placeuvote.android;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.*;
+import android.widget.TextView;
+import android.widget.ListView;
+import android.widget.AdapterView;
+//import android.widget.ListAdapter;
+import android.widget.ArrayAdapter;
+import android.widget.AdapterView.OnItemClickListener; 
+import android.util.Log;
+//import java.util.ArrayList;
+import java.net.URL;
+
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.xml.sax.InputSource;
+
+import org.xml.sax.XMLReader;
+
+import android.content.Intent;
+
+import com.placeuvote.android.R;
+import com.placeuvote.android.ShowDescription;
+
+public class RSSReader extends Activity implements OnItemClickListener
+{
+
+	public final String PUVFEED = "http://www.placeuvote.com/polls.rss";
+	// public final String RSSFEEDOFCHOICE = "http://www.ibm.com/developerworks/views/rss/customrssatom.jsp?zone_by=XML&zone_by=Java&zone_by=Rational&zone_by=Linux&zone_by=Open+source&zone_by=WebSphere&type_by=Tutorials&search_by=&day=1&month=06&year=2007&max_entries=20&feed_by=rss&isGUI=true&Submit.x=48&Submit.y=14";
+	
+	public final String tag = "RSSReader";
+	private RSSFeed feed = null;
+	
+	/** Called when the activity is first created. */
+
+    public void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        setContentView(R.layout.main);
+        
+        // go get our feed!
+        feed = getFeed(PUVFEED);
+
+        // display UI
+        UpdateDisplay();
+        
+    }
+
+    
+    private RSSFeed getFeed(String urlToRssFeed)
+    {
+    	try
+    	{
+    		// setup the url
+    	   URL url = new URL(urlToRssFeed);
+
+           // create the factory
+           SAXParserFactory factory = SAXParserFactory.newInstance();
+           // create a parser
+           SAXParser parser = factory.newSAXParser();
+
+           // create the reader (scanner)
+           XMLReader xmlreader = parser.getXMLReader();
+           // instantiate our handler
+           RSSHandler theRssHandler = new RSSHandler();
+           // assign our handler
+           xmlreader.setContentHandler(theRssHandler);
+           // get our data via the url class
+           InputSource is = new InputSource(url.openStream());
+           // perform the synchronous parse           
+           xmlreader.parse(is);
+           // get the results - should be a fully populated RSSFeed instance, or null on error
+           return theRssHandler.getFeed();
+    	}
+    	catch (Exception ee)
+    	{
+    		// if we have a problem, simply return null
+    		return null;
+    	}
+    }
+    public boolean onCreateOptionsMenu(Menu menu) 
+    {
+    	super.onCreateOptionsMenu(menu);
+    	
+    //	menu.add(0,0,"Choose RSS Feed");
+    //	menu.add(0,1,"Refresh");
+    	Log.i(tag,"onCreateOptionsMenu");
+    	return true;
+    }
+    
+ /*   public boolean onOptionsItemSelected(Menu.Item item){
+        switch (item.getId()) {
+        case 0:
+        	
+        	Log.i(tag,"Set RSS Feed");
+            return true;
+        case 1:
+        	Log.i(tag,"Refreshing RSS Feed");
+            return true;
+        }
+        return false;
+    }
+  */  
+    
+    private void UpdateDisplay()
+    {
+        TextView feedtitle = (TextView) findViewById(R.id.feedtitle);
+        TextView feedpubdate = (TextView) findViewById(R.id.feedpubdate);
+        ListView itemlist = (ListView) findViewById(R.id.itemlist);
+  
+        
+        if (feed == null)
+        {
+        	feedtitle.setText("No RSS Feed Available");
+        	return;
+        }
+        
+        feedtitle.setText(feed.getTitle());
+        feedpubdate.setText(feed.getPubDate());
+
+        ArrayAdapter<RSSItem> adapter = new ArrayAdapter<RSSItem>(this,android.R.layout.simple_list_item_1,feed.getAllItems());
+
+        itemlist.setAdapter(adapter);
+        
+        itemlist.setOnItemClickListener(this);
+        
+        itemlist.setSelection(0);
+        
+    }
+    
+    
+     public void onItemClick(AdapterView parent, View v, int position, long id)
+     {
+    	 Log.i(tag,"item clicked! [" + feed.getItem(position).getTitle() + "]");
+
+    	 Intent itemintent = new Intent(this, ShowDescription.class);
+         
+    	 Bundle b = new Bundle();
+    	 b.putString("title", feed.getItem(position).getTitle());
+    	 b.putString("description", feed.getItem(position).getDescription());
+    	 b.putString("link", feed.getItem(position).getLink());
+    	 b.putString("pubdate", feed.getItem(position).getPubDate());
+    	 
+    	 itemintent.putExtra("android.intent.extra.INTENT", b);
+    	 startActivity(itemintent);
+     }
+    
+}
+