Commits

littledot5566 committed 6e53991

Implemented HistoryActivity to display past Expeditions.

Comments (0)

Files changed (19)

AndroidManifest.xml

         <!--  -->
         <activity android:name=".components.TestBundleActivity" >
         </activity>
+        <!--  -->
+        <activity android:name=".components.HistoryActivity" >
+        </activity>
     </application>
 
 </manifest>
+* Continue active expedition
+* Expedition list in ListView form

release/treasure-hunter-ideas.txt

+Android Application Treasure Hunter Ideas
+
+The pitch:
+
+Treasure Hunter is an app that promotes exercise by getting users out of their seats!
+For to long have users been stranded inside their houses, we're here to save them from their couches!
+
+The idea behind Treasure Hunter is similar to the childhood game Hot-Warm-Cold, where the protagonist, who does not know the location of the treasure, must depend on the other participants in the game to guide him/her by giving hints of either "hotter" or "colder".
+
+In this app, the user first sets a distance bracket of how much he/she would like to travel. The application then randomly generates a destination where the user must travel to to unveil his treasures.
+
+(Ex1) Distance brackets:
+1-100m, 100-300m, 300-500m, 500-1km, 1-2km, etc.
+
+Once the destination has been set and the user can proceed, the screen will display the distance between the user and the user's destination. As the user approaches the destination, the distance shrinks. Until a reasonable threshold (say 10% of the total distance to travel) is reached, the app notifies that the user is close enough and displays a "collect treasure" button like those cheesy phishing websites. The user finally taps the button to claim his hard-earned prize.
+
+(Ex2) The "collect treasure" button
++--------------+
+|Start Digging!|
++--------------+
+
+This is just what we call "soft-core" mode. The user knows the exact distance to travel. We can kick that up a notch by introducing "hard-core" mode. Instaed of showing the exact distance, we only display keywords such as "arctic ice", "freezing cold", "cool", "warm", "hot", "burning sun", etc. as the user travels. Some problems could arise with this: if the target distance is super far (like 5km) and there are not enough identifiers (say 5), each identifier would have to span 1km, that would leave the user clueless where to go. Ideally, each identifier should span 100-200m so that users wouldn't be left walking in vain, but isn't that the point in the first place, walking for a virtual reward?
+
+We can also kick it down a notch by creating "kiddie-mode", which basically includes a map and routes the kids' travel path.
+
+(Ex3) Hard-core mode
++---------------------------------+
+|Brr... It's freezing cold here...|
+|Let's start moving...            |
+|(no distance shown at all)       |
++---------------------------------+
+
+In some cases, the location might be private property which the user cannot trespass, or on an island where you must swim accross. We're not that hard-core, so in cases where the destination cannot be reached, we offer an exit strategy so that your progress will not go into the drain. Accompanying the "collect treasure" button, we provide a "dig now" button that is shown at all times. The "dig now" button allows the user to dig for treasure where the user is, but of course the "value" of the prize will be at a discount relative to the distance travelled. So if the user were outside a private company building where the user's destination is and can't get in, tap the "dig now" button and collect the prize, which shouldn't be too shabby compared to the full prize because the user was almost there.
+
+(Ex4) Unreachable destinations
++---------------------------+
+|I'll settle for digging now|
++---------------------------+
+
+Some people have negative opinions of where their destination. It might be a morgue, a cemetary, a nuclear power plant, etc. In these cases, we provide another exit strategy, an "I don't want to go there" button. The user is also rewarded accordingly similar to the unreachable case, but the application takes note of this decision and will never include the frowned-upon location in the pool of possible destination again.
+
+(Ex5) Scary/Dangerous destinations
++------------------------------------------+
+|This place is creepy... Get me outta here!|
++------------------------------+-----------+
+|It's too dangerous to proceed!|
++------------------------------+
+
+
+Business model:
+
+This app can bring people to places, which means it can bring users/customers straight to your  door. Say you have a huge sale, you advertise using the traditional methods, but customers don't always go to your event, especially if you are a local shop owner. With this app, we can send customers your way.
+Once there, give the user incentives to Tweet or share on Facebook by offering an extra prize or something, now you get more publicity, and it is through friends!
+
+
+
+Roadblocks:
+
+Data, data, data. Need location data of destinations. Google Places? OpenStreetMaps?
+Android, Android, Android. Need to master Location & GPS protocols. Phone power consumption is also a great concern.

res/layout/history_act_layout.xml

+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    android:orientation="vertical" >
+
+    <ListView
+        android:id="@+id/history_lv_expeditions"
+        android:layout_width="fill_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" />
+
+</LinearLayout>

res/layout/history_item.xml

+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical" >
+
+    <TextView
+        android:id="@+id/hItem_tv_user"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content" />
+
+    <TextView
+        android:id="@+id/hItem_tv_stTime"
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content" />
+
+</LinearLayout>

res/layout/main_act_layout.xml

         android:onClick="onClick"
         android:text="View my profile" />
 
+    <Button
+        android:id="@+id/main_but_continue"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:onClick="onClick"
+        android:text="Continue expedition" />
+
+    <Button
+        android:id="@+id/main_but_history"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:onClick="onClick"
+        android:text="History" />
+
 </LinearLayout>

src/nctuw/littledot/localtreasure/Const.java

+package nctuw.littledot.localtreasure;
+
+public class Const {
+	public static final String BUNDLE_SOURCE = "source";
+	public static final String BUNDLE_EID = "eID";
+	public static final String BUNDLE_PROFILE = "userProfile";
+	public static final String BUNDLE_DISTANCE = "distance";
+}

src/nctuw/littledot/localtreasure/ExpeditionActivity.java

 import android.os.Bundle;
 import android.view.Menu;
 import android.view.View;
-import android.widget.ShareActionProvider;
 import android.widget.TextView;
 
 import com.google.android.maps.GeoPoint;
 		// getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 		mLM = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
 		mSM = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
-		mDB = new Database(this);
+		mDB = new Database(this).open(Database.MODE_WRITE);
 		mSP = new SPManager(this);
 
 		// initialize map widgets
 			Echo.a(this, String.format("bundle=%s", mExpedition.toString()));
 
 		} else {
-			// initialize Expedition
-			mExpedition = new Expedition();
-			mExpedition.setPID(mSP.getActiveProfileID());
-			mExpedition.setStartTS(System.currentTimeMillis());
-
+			// resume or start a new Expedition
 			Bundle extras = getIntent().getExtras();
-			mExpedition.setDistance(extras.getFloat(
-					SelectDistanceActivity.BUNDLE_DISTANCE, 0));
-
-			long eID = mDB.insertExpedition(mExpedition);
-			mExpedition.setEID(eID);
-			mSP.setActiveExpeditionID(eID);
+			String source = extras.getString(Const.BUNDLE_SOURCE);
+
+			if (source.equals(SelectDistanceActivity.class)) {
+				// initialize Expedition
+				mExpedition = new Expedition();
+				mExpedition.setPID(mSP.getActiveProfileID());
+				mExpedition.setStartTS(System.currentTimeMillis());
+				mExpedition.setDistance(extras.getFloat(Const.BUNDLE_DISTANCE, 0));
+
+			} else if (source.equals(MainActivity.class.getName())) {
+				// load saved Expedition
+				long eID = extras.getLong(Const.BUNDLE_EID);
+				mExpedition = mDB.queryExpedition(eID);
+
+				startMarker.clearOverlay();
+				startMarker.addLocation(mExpedition.getStartLoc(), "resume-Start",
+						mExpedition.getStartLoc().toString());
+				destMarker.clearOverlay();
+				destMarker.addLocation(mExpedition.getDestLoc(), "resume-Dest",
+						mExpedition.getDestLoc().toString());
 
-			// randomize direction, calculate destination if current location is
-			// set
-			// mBearing = Math.random() * 360;
+			}
+			Leg.a(mExpedition.toString());
 
-			showDialog(LOCATION_LOCK_DIALOG);
+			if (!isCalibrated)
+				showDialog(LOCATION_LOCK_DIALOG);
 
 			/*
 			 * // get a fresh start, only concerns are time & accuracy Time time
 		}
 	}
 
-	public void onClick(View v) {
-		int id = v.getId();
-		if (id == R.id.hunt_but_showmap) {
-			Intent showmap = new Intent(this, HuntingMapActivity.class);
-			startActivity(showmap);
-		} else if (id == R.id.map_but_debug) {
-			Intent test = new Intent(this, TestBundleActivity.class);
-			mExpedition.setEndTS(System.currentTimeMillis());
-			test.putExtra(BUND_EXPEDITION, mExpedition);
-			Leg.a(mExpedition.toString());
-			startActivity(test);
-		}
-	}
-
 	@Override
 	protected void onResume() {
 		super.onResume();
 			Leg.a("provider=" + provider);
 
 			mLM.requestLocationUpdates(provider, 0, (float) (mExpedition
-					.getDistance() * 0.05 < 10 ? 10
-					: mExpedition.getDistance() * 0.05), this);
+					.getDistance() * 0.05 < 10 ? 10 : mExpedition.getDistance() * 0.05),
+					this);
 		}
 
 		// register sensor updates
-		mSM.registerListener(this,
-				mSM.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
+		mSM.registerListener(this, mSM.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
 				SensorManager.SENSOR_DELAY_UI);
 		mSM.registerListener(this,
 				mSM.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
 
 		mExpedition.setEndTS(System.currentTimeMillis());
 
-		// flush expedition to disk
-		mDB.updateExpedition(mExpedition);
+		// save only after destination is confirmed
+		if (mExpedition.getDestLoc() != null)
+			mDB.updateExpedition(mExpedition);
 
 		mDB.close();
 		mLM.removeUpdates(this);
 		Leg.a(String.format("expedition=%s", mExpedition.toString()));
 	}
 
+	public void onClick(View v) {
+		int id = v.getId();
+		if (id == R.id.hunt_but_showmap) {
+			Intent showmap = new Intent(this, HuntingMapActivity.class);
+			startActivity(showmap);
+		} else if (id == R.id.map_but_debug) {
+			Intent test = new Intent(this, TestBundleActivity.class);
+			mExpedition.setEndTS(System.currentTimeMillis());
+			test.putExtra(BUND_EXPEDITION, mExpedition);
+			Leg.a(mExpedition.toString());
+			startActivity(test);
+		}
+	}
+
 	@Override
 	public boolean onCreateOptionsMenu(Menu menu) {
 		getMenuInflater().inflate(R.menu.activity_main, menu);
 
 		// mCurLocation = location;
 
-		mController.setCenter(new GeoPoint(
-				(int) (location.getLatitude() * 1E6), (int) (location
-						.getLongitude() * 1E6)));
+		mController.setCenter(new GeoPoint((int) (location.getLatitude() * 1E6),
+				(int) (location.getLongitude() * 1E6)));
 		playerMarker.clearOverlay();
 		playerMarker.addLocation(location, "CurLoc", location.toString());
 
 
 			double bearing = Math.random() * 360;
 			mExpedition.setStartLoc(location);
-			mExpedition.setDestLoc(Geodesy.calculateVincentyDestination(
-					location, bearing, mExpedition.getDistance()));
+			mExpedition.setDestLoc(Geodesy.calculateVincentyDestination(location,
+					bearing, mExpedition.getDistance()));
+
+			// save only after destination is confirmed
+			long eID = mDB.insertExpedition(mExpedition);
+			mExpedition.setEID(eID);
+			mSP.setActiveExpeditionID(eID);
 
 			startMarker.clearOverlay();
-			startMarker
-					.addLocation(location, "Cali-Start", location.toString());
+			startMarker.addLocation(location, "Cali-Start", location.toString());
 			destMarker.clearOverlay();
-			destMarker.addLocation(mExpedition.getDestLoc(), "Cali-Dest",
-					mExpedition.getDestLoc().toString());
+			destMarker.addLocation(mExpedition.getDestLoc(), "Cali-Dest", mExpedition
+					.getDestLoc().toString());
 
 			isCalibrated = true;
 

src/nctuw/littledot/localtreasure/HuntingActivity.java

 
 import java.util.List;
 
-import nctuw.littledot.localtreasure.components.SelectDistanceActivity;
 import nctuw.littledot.util.Echo;
 import nctuw.littledot.util.Leg;
 import android.app.Dialog;
 import android.view.View;
 import android.widget.TextView;
 
-import com.google.android.maps.GeoPoint;
 import com.google.android.maps.MapActivity;
-import com.google.android.maps.MapView;
 import com.google.android.maps.Overlay;
-import com.google.android.maps.OverlayItem;
 
 public class HuntingActivity extends MapActivity implements LocationListener,
 		SensorEventListener {
-	public static final long		LOCATION_TIME_THRESH	= 5 * 60 * 1000;
-	public static final float		LOCATION_ACC_THRESH		= 100.0f;
-	public static final int			LOCATION_LOCK_DIALOG	= 1;
+	public static final long LOCATION_TIME_THRESH = 5 * 60 * 1000;
+	public static final float LOCATION_ACC_THRESH = 100.0f;
+	public static final int LOCATION_LOCK_DIALOG = 1;
 
-	public static final String	BUND_DIST							= "dist";
-	public static final String	BUND_BEAR							= "bear";
-	public static final String	BUND_CURRLOC					= "curr";
-	public static final String	BUND_DESTLOC					= "dest";
+	public static final String BUND_DIST = "dist";
+	public static final String BUND_BEAR = "bear";
+	public static final String BUND_CURRLOC = "curr";
+	public static final String BUND_DESTLOC = "dest";
 
-	private LayoutInflater			mLI;
-	private LocationManager			mLM;
-	private SensorManager				mSM;
+	private LayoutInflater mLI;
+	private LocationManager mLM;
+	private SensorManager mSM;
 
-	private TextView						tvCurLoc;
-	private TextView						tvDestLoc;
-	private TextView						tvDistance;
-	private TextView						tvBearing;
+	private TextView tvCurLoc;
+	private TextView tvDestLoc;
+	private TextView tvDistance;
+	private TextView tvBearing;
 
-	private ProgressDialog			pdLock;
+	private ProgressDialog pdLock;
 
-	private int									mDistance;
-	private double							mBearing;
-	private Location						mCurLocation;
-	private Location						mDestLocation;
-	private boolean							mRecalibrate					= true;
+	private int mDistance;
+	private double mBearing;
+	private Location mCurLocation;
+	private Location mDestLocation;
+	private boolean mRecalibrate = true;
 
-	private float								mAcceler[];
-	private float								mMagnetic[];
-	private List<Overlay>				mapOverlays;
+	private float mAcceler[];
+	private float mMagnetic[];
+	private List<Overlay> mapOverlays;
 
 	/*
 	 * Base class Activity
 
 		} else {
 			Bundle extras = getIntent().getExtras();
-			mDistance = extras.getInt(SelectDistanceActivity.BUNDLE_DISTANCE, 0);
+			mDistance = extras.getInt(Const.BUNDLE_DISTANCE, 0);
 
 			// get a fresh start, only concerns are time & accuracy
 			Time time = new Time();

src/nctuw/littledot/localtreasure/MainActivity.java

 package nctuw.littledot.localtreasure;
 
+import nctuw.littledot.localtreasure.components.HistoryActivity;
 import nctuw.littledot.localtreasure.components.ProfileActivity;
 import nctuw.littledot.localtreasure.components.SelectDistanceActivity;
 import nctuw.littledot.localtreasure.database.Database;
 import nctuw.littledot.localtreasure.database.Profile;
 import nctuw.littledot.localtreasure.database.SPManager;
-import nctuw.littledot.localtreasure.database.Treasure;
 import nctuw.littledot.util.Leg;
 import android.app.Activity;
 import android.app.Dialog;
 import android.os.Bundle;
 import android.view.Menu;
 import android.view.View;
+import android.widget.Button;
 import android.widget.TextView;
 
 public class MainActivity extends Activity {
 	public static final String BUN_PROFILE = "bunProfile";
+	public static final String BUN_EID = "bunEID";
 	private TextView tvInfo;
 
 	private Database mDB;
 	private SPManager mSPManager;
 	private Profile mProfile;
 
+	private Button butContinue;
+
+	private long mActiveEID = 0;
+
 	@Override
 	protected void onCreate(Bundle savedInstanceState) {
 		super.onCreate(savedInstanceState);
 
 		setContentView(R.layout.main_act_layout);
+		butContinue = (Button) findViewById(R.id.main_but_continue);
 		tvInfo = (TextView) findViewById(R.id.main_tv_info);
 
 		mSPManager = new SPManager(this);
 		mDB = new Database(this);
 		mDB.open(Database.MODE_WRITE);
+
+		// load active profile
 		mProfile = mDB.queryProfile(mSPManager.getActiveProfileID());
 		Leg.a(mProfile.toString());
 
 		// check for active expeditions
-		long eID = mSPManager.getActiveExpeditionID();
-		Leg.a("Active expedition=" + eID);
+		mActiveEID = mSPManager.getActiveExpeditionID();
+		butContinue.setText("Continue Expedition=" + mActiveEID);
 
 		tvInfo.setText(mProfile.toString());
 	}
 
 		if (id == R.id.main_but_startExpedition) {
 			Intent intent = new Intent(this, SelectDistanceActivity.class);
+			intent.putExtra(Const.BUNDLE_SOURCE, getClass().getName());
 			startActivity(intent);
+
 		} else if (id == R.id.main_but_profile) {
 			Intent intent = new Intent(this, ProfileActivity.class);
-			intent.putExtra(BUN_PROFILE, mProfile);
+			intent.putExtra(Const.BUNDLE_SOURCE, getClass().getName());
+			intent.putExtra(Const.BUNDLE_PROFILE, mProfile);
 			startActivity(intent);
+
+		} else if (id == R.id.main_but_continue) {
+			Intent intent = new Intent(this, ExpeditionActivity.class);
+			intent.putExtra(Const.BUNDLE_SOURCE, getClass().getName());
+			intent.putExtra(Const.BUNDLE_EID, mActiveEID);
+			startActivity(intent);
+
+		} else if (id == R.id.main_but_history) {
+			Intent intent = new Intent(this, HistoryActivity.class);
+			intent.putExtra(Const.BUNDLE_SOURCE, getClass().getName());
+			startActivity(intent);
+
 		}
 	}
 }

src/nctuw/littledot/localtreasure/components/ExpeditionAdapter.java

+package nctuw.littledot.localtreasure.components;
+
+import java.util.ArrayList;
+
+import nctuw.littledot.localtreasure.R;
+import nctuw.littledot.localtreasure.database.Database;
+import nctuw.littledot.localtreasure.database.Expedition;
+import nctuw.littledot.localtreasure.database.Profile;
+import nctuw.littledot.util.Leg;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.DatabaseUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.TextView;
+
+public class ExpeditionAdapter extends BaseAdapter {
+	private Context mCtx;
+	private Database mDB;
+
+	private ArrayList<ContentValues> mData = new ArrayList<ContentValues>();
+
+	public ExpeditionAdapter(Context ctx) {
+		mCtx = ctx;
+		mDB = new Database(ctx).open(Database.MODE_READ);
+
+		Cursor cur = mDB.rawQuery(String
+				.format("select * from %s, %s where %s.%s=%s.%s order by %s",
+						Expedition.TABLE_NAME, Profile.TABLE_NAME,
+						Expedition.TABLE_NAME, Expedition.KEY_USER_ID,
+						Profile.TABLE_NAME, Profile.KEY_ID,
+						Expedition.KEY_START_TIMESTAMP));
+
+		if (!cur.moveToFirst())
+			throw new IllegalAccessError("bad sql");
+
+		while (!cur.isAfterLast()) {
+			Leg.a(DatabaseUtils.dumpCurrentRowToString(cur));
+			ContentValues kv = Expedition.toContentValues(cur);
+			kv.putAll(Profile.toContentValues(cur));
+			mData.add(kv);
+
+			cur.moveToNext();
+		}
+
+		cur.close();
+		mDB.close();
+	}
+
+	public int getCount() {
+		return mData.size();
+	}
+
+	public ContentValues getItem(int position) {
+		return mData.get(position);
+	}
+
+	public long getItemId(int position) {
+		return mData.get(position).getAsLong(Expedition.KEY_ID);
+	}
+
+	public View getView(int position, View view, ViewGroup parent) {
+		if (view == null) {
+			LayoutInflater inflater = (LayoutInflater) mCtx
+					.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+			view = inflater.inflate(R.layout.history_item, parent, false);
+		}
+
+		ContentValues kv = mData.get(position);
+
+		TextView tvUser = (TextView) view.findViewById(R.id.hItem_tv_user);
+		TextView tvStTime = (TextView) view.findViewById(R.id.hItem_tv_stTime);
+
+		tvUser.setText(kv.getAsString(Profile.KEY_NAME));
+		tvStTime.setText(kv.getAsLong(Expedition.KEY_START_TIMESTAMP).toString());
+
+		return view;
+	}
+}

src/nctuw/littledot/localtreasure/components/HistoryActivity.java

+package nctuw.littledot.localtreasure.components;
+
+import nctuw.littledot.localtreasure.R;
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.ListView;
+
+public class HistoryActivity extends Activity {
+	private ListView lvHistory;
+
+	private ExpeditionAdapter mAdapter;
+
+	@Override
+	protected void onCreate(Bundle savedInstanceState) {
+		super.onCreate(savedInstanceState);
+
+		setContentView(R.layout.history_act_layout);
+		lvHistory = (ListView) findViewById(R.id.history_lv_expeditions);
+
+		mAdapter = new ExpeditionAdapter(this);
+		lvHistory.setAdapter(mAdapter);
+	}
+
+	@Override
+	protected void onResume() {
+		super.onResume();
+	}
+
+	@Override
+	protected void onPause() {
+		super.onPause();
+	}
+
+}

src/nctuw/littledot/localtreasure/components/ProfileActivity.java

 package nctuw.littledot.localtreasure.components;
 
+import nctuw.littledot.localtreasure.Const;
 import nctuw.littledot.localtreasure.MainActivity;
 import nctuw.littledot.localtreasure.R;
 import nctuw.littledot.localtreasure.database.Database;
 
 public class ProfileActivity extends Activity {
 	// widgets
-	private TextView	tvName;
-	private TextView	tvExpeditionTotal;
-	private TextView	tvTotalDistance;
-	private TextView	tvTimeTotal;
-	private GridView	gvTreasure;
+	private TextView tvName;
+	private TextView tvExpeditionTotal;
+	private TextView tvTotalDistance;
+	private TextView tvTimeTotal;
+	private GridView gvTreasure;
 
-	private Database	mDB	= new Database(this);
-	private Profile		mProfile;
+	private Database mDB = new Database(this);
+	private Profile mProfile;
 
 	@Override
 	protected void onCreate(Bundle savedInstanceState) {
 		gvTreasure = (GridView) findViewById(R.id.profile_gv_treasure);
 
 		Bundle bundle = getIntent().getExtras();
-		mProfile = bundle.getParcelable(MainActivity.BUN_PROFILE);
+		mProfile = bundle.getParcelable(Const.BUNDLE_PROFILE);
 		Leg.a(mProfile.toString());
 
 		tvName.setText(mProfile.getName());

src/nctuw/littledot/localtreasure/components/SelectDistanceActivity.java

 package nctuw.littledot.localtreasure.components;
 
+import nctuw.littledot.localtreasure.Const;
 import nctuw.littledot.localtreasure.ExpeditionActivity;
 import nctuw.littledot.localtreasure.R;
-import nctuw.littledot.localtreasure.R.id;
-import nctuw.littledot.localtreasure.R.layout;
 import android.app.Activity;
 import android.content.Intent;
 import android.os.Bundle;
 import android.widget.EditText;
 
 public class SelectDistanceActivity extends Activity {
-	public static String	BUNDLE_DISTANCE	= "bundle_distance";
 
 	@Override
 	protected void onCreate(Bundle savedInstanceState) {
 
 		switch (v.getId()) {
 			case R.id.distance_but_500m:
-				intent.putExtra(BUNDLE_DISTANCE, 500F);
+				intent.putExtra(Const.BUNDLE_SOURCE, getClass().getName());
+				intent.putExtra(Const.BUNDLE_DISTANCE, 500F);
 				break;
 		}
 
 			but.setText("OK!");
 		} else {
 			Intent intent = new Intent(this, ExpeditionActivity.class);
-			intent.putExtra(BUNDLE_DISTANCE,
+			intent.putExtra(Const.BUNDLE_SOURCE, getClass().getName());
+			intent.putExtra(Const.BUNDLE_DISTANCE,
 					Float.parseFloat(et.getText().toString()));
 			startActivity(intent);
 		}

src/nctuw/littledot/localtreasure/database/Database.java

 package nctuw.littledot.localtreasure.database;
 
+import java.util.ArrayList;
+
 import nctuw.littledot.util.Leg;
-import android.content.BroadcastReceiver.PendingResult;
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
 	public Database(Context ctx) {
 		this.mContext = ctx;
 		DBHelper = new DatabaseHelper(mContext);
-
 	}
 
 	private class DatabaseHelper extends SQLiteOpenHelper {
 		DatabaseHelper(Context context) {
-			super(context, DBNAME, null, DB_VERSION);
+			super(context, context.getPackageName(), null, DB_VERSION);
 		}
 
 		@Override
 		}
 	}
 
-	public void open(int mode) {
+	public Database open(int mode) {
 		if (mode == MODE_WRITE)
 			db = DBHelper.getWritableDatabase();
 		else if (mode == MODE_READ)
 			db = DBHelper.getReadableDatabase();
 		else
 			throw new IllegalArgumentException("Unknown access argument");
+		return this;
 	}
 
 	public void close() {
 	/*************/
 
 	public Cursor rawQuery(String sql) {
-		return rawQuery(sql, null);
-	}
-
-	public Cursor rawQuery(String sql, String[] args) {
-		Cursor cur = db.rawQuery(sql, args);
-
-		if (cur.moveToFirst())
-			return cur;
-		else
-			return null;
+		return db.rawQuery(sql, null);
 	}
 
 	/*
 		Cursor cur = rawQuery(String.format("select * from %s where %s=%d",
 				Profile.TABLE_NAME, Profile.KEY_ID, profileID));
 
-		if (cur != null) {
+		if (cur.moveToFirst()) {
 			Leg.dumpCursor(cur);
 			Profile profile = new Profile();
 			profile.setProfileID(profileID);
 			// profile.setTotalDistance(cur.getDouble(cur
 			// .getColumnIndex(KEY_PROFILE_EXPEDITIONS)));
 
+			cur.close();
+
 			return profile;
 		} else
 			return null;
 	}
 
+	public Expedition queryExpedition(long eID) {
+		String query = new StringBuilder("select * from ")
+				.append(Expedition.TABLE_NAME).append(" where ")
+				.append(Expedition.KEY_ID).append("=").append(eID).toString();
+
+		Cursor cur = rawQuery(query);
+
+		if (cur.moveToFirst()) {
+			Expedition e = new Expedition(cur);
+			cur.close();
+			return e;
+		} else
+			return null;
+	}
+
+	public ArrayList<Expedition> queryExpeditions(String where) {
+		String query = "";
+		if (where.equals("*"))
+			query = new StringBuilder("select * from ")
+					.append(Expedition.TABLE_NAME).toString();
+
+		Cursor cur = rawQuery(query);
+
+		if (cur.moveToFirst()) {
+			ArrayList<Expedition> expeditions = new ArrayList<Expedition>();
+
+			while (!cur.isAfterLast()) {
+				expeditions.add(new Expedition(cur));
+				cur.moveToNext();
+			}
+			cur.close();
+
+			return expeditions;
+		} else
+			return null;
+	}
+
 	/*************/
 	/** Inserts **/
 	/*************/
 	}
 
 	public long insertExpedition(Expedition expedition) {
-		return db.insert(Expedition.TABLE_NAME, null,
+		return db.insertOrThrow(Expedition.TABLE_NAME, null,
 				expedition.toContentValues());
 	}
 
 	public long insertProfile(Profile profile) {
-		return db.insert(Profile.TABLE_NAME, null,
-				profile.toContentValues());
+		return db.insert(Profile.TABLE_NAME, null, profile.toContentValues());
 	}
 
 	/*************/
 		return kvPair;
 	}
 
+	/**
+	 * Checks if the value is null before returning the column index.
+	 * 
+	 * @param c
+	 * @param s
+	 * @return
+	 */
+	public static int getIndex(Cursor c, String s) {
+		// column index starts at 0
+		int i = c.getColumnIndex(s);
+		if (c.isNull(i))
+			return -1;
+		else
+			return i;
+	}
+
 }

src/nctuw/littledot/localtreasure/database/Expedition.java

 import java.util.ArrayList;
 import java.util.Date;
 
+import org.json.JSONObject;
+
+import nctuw.littledot.util.Leg;
 import android.content.ContentValues;
+import android.database.Cursor;
 import android.location.Location;
 import android.os.Parcel;
 import android.os.Parcelable;
 	private long eID = 0;
 
 	private long pID = 0;
-	private Location mStartLoc;
-	private Location mDestLoc;
+	private Location mStartLoc = null;
+	private Location mDestLoc = null;
 	private float mDistance;
 	private float mTravelled;
 
 	private long mStartTS;
 	private long mEndTS;
 
-	private Treasure mPrize;
+	private Treasure mPrize = null;
 
-	private Location mLKLocation;
+	private Location mLKLocation = null;
 
 	/************/
 	/** SQLite **/
 	public static final String SQL_CREATE_EXPEDITION = "create table if not exists "
 			+ TABLE_NAME
 			+ "("
-			+ KEY_ID
+			+ KEY_ID // long
 			+ " integer not null primary key autoincrement,"
-			+ KEY_USER_ID
+			+ KEY_USER_ID // long
 			+ " integer not null,"
-			+ KEY_DISTANCE
+			+ KEY_DISTANCE // float
 			+ " real not null default 0,"
-			+ KEY_TRAVELED
+			+ KEY_TRAVELED // float
 			+ " real default 0,"
-			+ KEY_START_LAT
+			+ KEY_START_LAT // double
 			+ " real,"
-			+ KEY_START_LONG
+			+ KEY_START_LONG // double
 			+ " real,"
-			+ KEY_END_LAT
+			+ KEY_END_LAT // double
 			+ " real,"
-			+ KEY_END_LONG
+			+ KEY_END_LONG // double
 			+ " real,"
-			+ KEY_START_TIMESTAMP
-			+ " integer,"
-			+ KEY_END_TIMESTAMP
+			+ KEY_START_TIMESTAMP // long
+			+ " integer not null,"
+			+ KEY_END_TIMESTAMP // long
 			+ " integer,"
-			+ KEY_TIME
+			+ KEY_TIME // long
 			+ " integer,"
-			+ KEY_TREASURE
+			+ KEY_TREASURE // int
 			+ " integer"
 			+ ");";
 
 	public Expedition() {
 	}
 
+	/**
+	 * Populate an Expedition via a Cursor.
+	 * 
+	 * @param cur
+	 */
+	public Expedition(Cursor cur) {
+		Leg.dumpCursor(cur);
+		Location loc = new Location("");
+		int i;
+
+		setEID(eID);
+		setPID(cur.getLong(cur.getColumnIndex(Expedition.KEY_USER_ID)));
+		setDistance(cur.getFloat(cur.getColumnIndex(Expedition.KEY_DISTANCE)));
+
+		if ((i = Database.getIndex(cur, Expedition.KEY_TRAVELED)) > -1)
+			setTravelled(cur.getFloat(i));
+
+		if ((i = Database.getIndex(cur, Expedition.KEY_START_LAT)) > -1) {
+			loc.setLatitude(cur.getDouble(i));
+			loc.setLongitude(cur.getDouble(cur
+					.getColumnIndex(Expedition.KEY_START_LONG)));
+			setStartLoc(loc);
+		}
+
+		if ((i = Database.getIndex(cur, Expedition.KEY_END_LAT)) > -1) {
+			loc.setLatitude(cur.getDouble(i));
+			loc.setLongitude(cur.getDouble(cur
+					.getColumnIndex(Expedition.KEY_END_LONG)));
+			setDestLoc(loc);
+		}
+
+		setStartTS(cur.getLong(cur
+				.getColumnIndex(Expedition.KEY_START_TIMESTAMP)));
+
+		if ((i = Database.getIndex(cur, Expedition.KEY_END_TIMESTAMP)) > -1)
+			setEndTS(cur.getLong(i));
+
+		if ((i = Database.getIndex(cur, Expedition.KEY_TREASURE)) > -1)
+			setPrize(Treasure.getTreasure(cur.getInt(i)));
+	}
+
 	public String toString() {
 		StringBuilder sb = new StringBuilder("ID=").append(eID);
+		sb.append(" pID=").append(pID);
 
 		if (mStartLoc != null)
 			sb.append(" stLoc=(").append(mStartLoc.getLatitude()).append(",")
 			keys.add(KEY_END_TIMESTAMP);
 			vals.add(mEndTS);
 			keys.add(KEY_TIME);
-			vals.add(mStartTS - mEndTS);
+			vals.add(mEndTS - mStartTS);
 		}
 		if (mPrize != null) {
 			keys.add(KEY_TREASURE);
 			vals.add(mPrize.getID());
 		}
-		return Database.toContentValues((String[]) keys.toArray(),
+
+		return Database.toContentValues(
+				(String[]) keys.toArray(new String[keys.size()]),
 				vals.toArray());
 	}
 
+	public static ContentValues toContentValues(Cursor c) {
+		ContentValues kv = new ContentValues();
+
+		kv.put(KEY_ID, c.getLong(c.getColumnIndex(KEY_ID)));
+		kv.put(KEY_USER_ID, c.getLong(c.getColumnIndex(KEY_USER_ID)));
+		kv.put(KEY_DISTANCE, c.getFloat(c.getColumnIndex(KEY_DISTANCE)));
+		kv.put(KEY_TRAVELED, c.getFloat(c.getColumnIndex(KEY_TRAVELED)));
+		kv.put(KEY_START_LAT, c.getDouble(c.getColumnIndex(KEY_START_LAT)));
+		kv.put(KEY_START_LONG, c.getDouble(c.getColumnIndex(KEY_START_LONG)));
+		kv.put(KEY_END_LAT, c.getDouble(c.getColumnIndex(KEY_END_LAT)));
+		kv.put(KEY_END_LONG, c.getDouble(c.getColumnIndex(KEY_END_LAT)));
+		kv.put(KEY_START_TIMESTAMP,
+				c.getLong(c.getColumnIndex(KEY_START_TIMESTAMP)));
+		kv.put(KEY_END_TIMESTAMP, c.getLong(c.getColumnIndex(KEY_END_TIMESTAMP)));
+		kv.put(KEY_TIME, c.getLong(c.getColumnIndex(KEY_TIME)));
+		kv.put(KEY_TREASURE, c.getInt(c.getColumnIndex(KEY_TREASURE)));
+
+		return kv;
+	}
+
 	public long getEID() {
 		return eID;
 	}
 
 	public void writeToParcel(Parcel dest, int flags) {
 		dest.writeLong(eID);
+		dest.writeLong(pID);
 		dest.writeParcelable(mStartLoc, 0);
 		dest.writeParcelable(mDestLoc, 0);
 		dest.writeFloat(mDistance);
 
 	private Expedition(Parcel in) {
 		eID = in.readLong();
+		pID = in.readLong();
 		mStartLoc = in.readParcelable(null);
 		mDestLoc = in.readParcelable(null);
 		mDistance = in.readFloat();

src/nctuw/littledot/localtreasure/database/Profile.java

 import java.util.ArrayList;
 
 import android.content.ContentValues;
+import android.database.Cursor;
 import android.os.Parcel;
 import android.os.Parcelable;
 
 			+ KEY_ID
 			+ " integer not null primary key autoincrement,"
 			+ KEY_NAME
-			+ " text default '<John Doe>',"
+			+ " text default '<John Doe>'"
 			+ ");";
 
 	public Profile() {
 				vals.toArray());
 	}
 
+	public static ContentValues toContentValues(Cursor c) {
+		ContentValues kv = new ContentValues();
+
+		kv.put(KEY_ID, c.getLong(c.getColumnIndex(KEY_ID)));
+		kv.put(KEY_NAME, c.getString(c.getColumnIndex(KEY_NAME)));
+
+		return kv;
+	}
+
 	public long getProfileID() {
 		return mProfileID;
 	}

src/nctuw/littledot/localtreasure/database/SPManager.java

 	public SPManager(Context ctx) {
 		mCtx = ctx;
 
-		mPrefs = mCtx.getSharedPreferences("nctuw.littledot.localtreasure",
+		mPrefs = mCtx.getSharedPreferences(ctx.getPackageName(),
 				Context.MODE_PRIVATE);
 
-		SharedPreferences.Editor editor = mPrefs.edit();
+		mEditor = mPrefs.edit();
 
 		// editor.putLong(Constants.PREF_LAST_AD_CLICK, cal.getTimeInMillis());
 		// editor.commit();

src/nctuw/littledot/localtreasure/database/Treasure.java

 		return values()[index];
 	}
 
+	public static Treasure getTreasure(int id) {
+		return values()[id - 1];
+	}
+
 	/**************************/
 	/** Interface Parcelable **/
 	/**************************/