src/nu/placebo/whatsup/network/OperationResult.java
public class OperationResult<T> {

	private int statusCode;
	private String statusMessage;
	private boolean hasErrors;
	private T result;
	private Action action;

	public OperationResult(boolean hasErrors, int statusCode,
			String statusMessage, T result) {
		this(hasErrors, statusCode, statusMessage, result, Action.DEFAULT);
	}

	public OperationResult(boolean hasErrors, int statusCode,
			String statusMessage, T result, Action action) {
		this.statusCode = statusCode;
		this.statusMessage = statusMessage;
		this.hasErrors = hasErrors;
		this.result = result;
		this.action = action;
	}

	public int getStatusCode() {
		return this.statusCode;
	}

	public String getStatusMessage() {
		return this.statusMessage;
	}

	public boolean hasErrors() {
		return this.hasErrors;
	}

	public T getResult() {
		return this.result;
	}

	public Action getAction() {
		return this.action;
	}

}
src/nu/placebo/whatsup/datahandling/DataProvider.java
public class DataProvider implements NetworkOperationListener<Annotation>, LocationListener {
	
	private Context c;
	/**
	 * Class is Singelton, disallow outside creation
	 */
	private DataProvider(Context c) {
		this.c = c;
		
		DatabaseConnectionLayer.setDatabaseHelper(new DatabaseHelper(c));
		Location lastKnownLocation = ((LocationManager) c.getSystemService(Context.LOCATION_SERVICE)).
													getLastKnownLocation(LocationManager.GPS_PROVIDER);
		if(lastKnownLocation == null) {
			lastKnownLocation = ((LocationManager) c.getSystemService(Context.LOCATION_SERVICE)).
												getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
		}
		if(lastKnownLocation == null) {
			addReferencePoint(new GeoPoint(57706900, 11982051), "physical_position");
			for(ReferencePoint rp : getAllReferencePoints()) {
				Log.i("Name is: ", rp.getName());
			}
			setCurrentReferencePoint(-1);
		} else {
			addReferencePoint(new GeoPoint((int)(lastKnownLocation.getLatitude() * 1000000 + 0.5),
					(int)(lastKnownLocation.getLongitude() * 1000000 + 0.5)),
					"physical_position");
			setCurrentReferencePoint(-1);
		}
	}
	
	private static volatile DataProvider instance;

	/**
	 * Gets the single instance of this class. The context parameter is only necessary the
	 * first call. Once instantiated, it can be null. For example, if a class does not have
	 * easy access to a contex and is sure that the DataProvider has been used earlier in
	 * the application lifetime, may call this with null rather than going to lengths to get
	 * a context.
	 * 
	 * @param c the context with which to create the database.
	 * @return
	 */
	public static DataProvider getDataProvider(Context c) {
		if(instance == null) {
			instance = new DataProvider(c);
		}
		return instance;
	}
	
	/**
	 * This method supplies the caller with a DataReturn<Annotation> object that will
	 * contain the annotation with the given id, if it has previously been saved to
	 * the database. If it was not found, the local data will be null, and the requester
	 * will have to wait until new server data is available.
	 * 
	 * @param nid
	 * @return
	 */
	public DataReturn<Annotation> getAnnotation(int nid) {
		
		DataReturn<Annotation> result;
		
		result = new DataReturn<Annotation>(DatabaseConnectionLayer.getAnnotation(nid),
						activeObjects.size());	
		activeObjects.add(result);
		AnnotationRetrieve ar = new AnnotationRetrieve(nid);
		ar.addOperationListener(result);
		new NetworkTask<Annotation>().execute(ar);
		return result;
	}
	
	/**
	 * Convenience method for getAnnotationMarkers(int, int, int, int) when you have two
	 * locations.
	 * 
	 * @param a one of the points
	 * @param b the other point
	 * @return 
	 */
	public DataReturn<List<GeoLocation>> getAnnotationMarkers(GeoLocation a, GeoLocation b) {
		return getAnnotationMarkers(a.getLocation().getLatitudeE6(), 
									a.getLocation().getLongitudeE6(),
									b.getLocation().getLatitudeE6(),
									b.getLocation().getLongitudeE6());
	}
	
	/**
	 * Calling this method is a request to get GeoLocations within
	 * the rectangular area given by applying the parameters 
	 * constraints.
	 * 
	 * @param latitudeA the latitude of the first point, in microlatitude
	 * @param longitudeA the longitude of the first point, in microlongitude
	 * @param latitudeB the latitude of the second point, in microlatitude
	 * @param longitudeB the longitude of the second point, in microlngitude
	 * @return a DataReturn object containing any local data found and which can
	 * be listened to by
	 */
	
	public DataReturn<List<GeoLocation>> getAnnotationMarkers(int latitudeA,
			int longitudeA, int latitudeB, int longitudeB) {
		int maxLat = Math.max(latitudeA, latitudeB);
		int maxLong = Math.max(longitudeA, longitudeB);
		int minLat = Math.min(latitudeA, latitudeB);
		int minLong = Math.min(longitudeA, longitudeB);

		DataReturn<List<GeoLocation>> result;
		GeoLocationsRetrieve glr = new GeoLocationsRetrieve(
				(latitudeA - 0.5) / 1000000, (longitudeA - 0.5) / 1000000,
				(latitudeB - 0.5) / 1000000, (longitudeB - 0.5) / 1000000);
		
		synchronized(this) {
			result = new DataReturn<List<GeoLocation>>(DatabaseConnectionLayer.getAnnotationMarkers(
											maxLat, maxLong, minLat, minLong), activeObjects.size());
			activeObjects.add(result);
		}
		glr.addOperationListener(result);
		new NetworkTask<List<GeoLocation>>().execute(glr);
		return result;
	}
	
	/**
	 * Gets the ReferencePoint that is currently used as reference point.
	 * In the case that the user has not chosen a reference point, the physical
	 * position of the phone is returned, as it is the standard refernce point.
	 * 
	 * @return the current reference point, as a ReferencePoint object.
	 */
	public ReferencePoint getCurrentReferencePoint() {
		return currentReferencePoint;
	}
	
	/**
	 * Returns all reference points saved in the database, and the physical
	 * position of the phone, which is always a reference point.
	 * 
	 * @return all reference point, including the physical location of the phone.
	 */
	public List<ReferencePoint> getAllReferencePoints() {
		return DatabaseConnectionLayer.getAllReferencePoints();
	}
	
	/**
	 * Sets the ReferencePoint to use as the current reference point, both short-time
	 * and in the database. Sending a negative id will set the physical location as
	 * current location (calling with the id of the physical location also works).
	 * 
	 * @param id the id of the already existing reference point. If the id does not
	 * match any existing reference point, nothing changes.
	 */
	public void setCurrentReferencePoint(int id) {
		currentReferencePoint = DatabaseConnectionLayer.setCurrentReferencePoint(id);
	}
	
	/**
	 * Adds a reference point to the database.
	 * 
	 * @param gp the geographical location of the reference point.
	 * @param name the name of the reference point.
	 */
	public void addReferencePoint(GeoPoint gp, String name) {
		DatabaseConnectionLayer.addReferencePoint(gp, name);
	}
		
	/**
	 * Removes a reference point from the database.
	 * 
	 * @param gl the point to remove
	 */
	public void removeReferencePoint(int id) {
		DatabaseConnectionLayer.removeReferencePoint(id);
	}
	
	/**
	 * Creates an Annotation with the specified values. A valid SessionInfo is required, and the object
	 * that wants the annotation should be sent as listener. The listener can be null if no object wants the
	 * returned Annotation immediately.
	 * 
	 * When the object is returned, the DataProvider will receive it as well, and it will be put into the
	 * database. The time until the annotation is stably in the database is determined by the workload of the
	 * phone, threading priority and the time a SQLite insert takes. As this is mostly random, trying to get
	 * this annotation from the database before it's fully updated will result
	 * 
	 * @param title
	 * @param desc
	 * @param author
	 * @param gp
	 * @param sInfo
	 * @param listener
	 */
	public void createAnnotation(String title, String desc, String author, 
			GeoPoint gp, SessionInfo sInfo, 
			NetworkOperationListener<Annotation> listener) {
		AnnotationCreate ac = new AnnotationCreate(title, desc, author, gp, sInfo);
		if(listener != null) {
			ac.addOperationListener(listener);
		}
		new NetworkTask<Annotation>().execute(ac);
	}
	
	public void createComment(int nid, String author, String commentText, String title,
							  NetworkOperationListener<Comment> listener) {
		SessionHandler sh = SessionHandler.getInstance(this.c);
		CommentCreate cc = new CommentCreate(title, commentText, nid,sh.getUserName(), sh.getSession());

		if(listener != null) {
			cc.addOperationListener(listener);
		}
		new NetworkTask<Comment>().execute(cc);
		DatabaseConnectionLayer.storeComment(nid, author, commentText, title);
	}
	
	/**
	 * Called by DataReturn object to notify the DataProvider about new data
	 * to insert into the local database.
	 * 
	 * @param newData whether the data differs from that in the local database
	 * @param id the id of the DataReturn that has finished
	 */
	@SuppressWarnings("unchecked")
	void newDataRecieved(boolean newData, int id) {
		if(newData) {
			OperationResult<?> result = activeObjects.get(id).getNewData();
			
			if(result == null || result.getResult() == null) {
				return;
			}
			if(!result.hasErrors()) {
				Object data = result.getResult();
				//Test what type the new data has		
				if(data.getClass() == Annotation.class) {
					if(!insertData((Annotation) data)) {
						//TODO Error handling
					}
				} else if(data.getClass() == List.class) {
					if(!insertData((List<GeoLocation>) data)) {
						//TODO Error handling
					}
				}
			}
		}
		activeObjects.remove(id);
	}
	
	//Inserts the given Annotation into its table, and it's auxiliary
	//information into their tables. If error occurs, false is returned.
	private boolean insertData(Annotation a) {
		return DatabaseConnectionLayer.storeAnnotation(a);
	}

	//Inserts the given list with GeoLocations into its table.
	//If error occurs, false is returned.
	private boolean insertData(List<GeoLocation> glList) {
		return DatabaseConnectionLayer.storeGeoLocations(glList);
	}

	private List<DataReturn<?>> activeObjects = new ArrayList<DataReturn<?>>();
	private ReferencePoint currentReferencePoint;

	public void operationExcecuted(OperationResult<Annotation> result) {
		if(!result.hasErrors()) {
			insertData(result.getResult());
		}
	}

	public void onLocationChanged(Location location) {
		DatabaseConnectionLayer.updateCurrentLocation(
				new GeoPoint((int)location.getLatitude(), (int)location.getLongitude()));
	}
	public void onProviderDisabled(String provider) {}
	public void onProviderEnabled(String provider) {}
	public void onStatusChanged(String provider, int status, Bundle extras) {}
}
src/nu/placebo/whatsup/constants/Constants.java
public class Constants {
	public static final int ALLOWED_CONCURRENT_CALLS = 2;
	public static final String API_URL = "http://whatsup.placebo.nu/api/";
	public static final int ACTIVITY_FINISHED_OK = 200;
	public static final int ACTIVITY_INTERRUPTED = 417;
	public static final int REFERENCE_POINT = 603;
	public static final int ANNOTATION = 606;
	public static final int LOG_IN = 609;
	public static final String PREFERENCES_FILE = "preferences";

}
src/nu/placebo/whatsup/util/GeoPointUtil.java
public class GeoPointUtil {

	/**
	 * Converts two GeoPoints and delivers an array with decimal degree doubles
	 * in the order:
	 * 
	 * minLat, minLong, maxLat, maxLong
	 * 
	 * The coordinates will be ordered in this manner regardless of which
	 * coordinate belongs to which GeoPoint
	 * 
	 * @param a
	 * @param b
	 * @return [minLat, minLong, maxLat, maxLong]
	 */
	public static double[] convertAreaToDoubles(GeoPoint a, GeoPoint b) {
		double[] result = new double[4];

		result[0] = ((double) Math.min(a.getLatitudeE6(), b.getLatitudeE6())) / 1000000;
		result[1] = ((double) Math.min(a.getLongitudeE6(), b.getLongitudeE6())) / 1000000;
		result[2] = ((double) Math.max(a.getLatitudeE6(), b.getLatitudeE6())) / 1000000;
		result[3] = ((double) Math.max(a.getLongitudeE6(), b.getLongitudeE6())) / 1000000;

		return result;
	}

	/**
	 * Converts a single GeoPoint to an array of decimal degree doubles
	 * 
	 * 
	 * @param a
	 * @return [lat, long]
	 */
	public static double[] convertGeoPointToDoubles(GeoPoint a) {
		double[] result = new double[2];

		result[0] = ((double) a.getLatitudeE6()) / 1000000;
		result[1] = ((double) a.getLongitudeE6()) / 1000000;

		return result;
	}

	/**
	 * Creates two GeoPoints with the center of the map, latitude span and longitude span
	 * 
	 * @param center - center of the current mapview
	 * @param latSpan - latitude span from bottom to top
	 * @param longSpan - longitude span from left to right
	 * @return GeoPoint[] with two GeoPoints representing the bottom-left and top-right coordinates 
	 */
	public static GeoPoint[] getBottomLeftToTopRightPoints(GeoPoint center,	int latSpan, int longSpan) {
		int bottom = center.getLatitudeE6() - (latSpan / 2);
		int top = center.getLatitudeE6() + (latSpan / 2);
		int left = center.getLongitudeE6() - (longSpan / 2);
		int right = center.getLongitudeE6() + (longSpan / 2);
		return new GeoPoint[] { new GeoPoint(bottom, left), new GeoPoint(top, right) };
	}

	/**
	 * Convenience method for packing a GeoPoint in a Bundle (android.os)
	 * 
	 * 
	 * 
	 * @see #popGeoPoint(Bundle)
	 * @see #bundleHasGeoPoint(Bundle)
	 * @param p
	 * @return Bundle with packaged GeoPoint
	 */
	public static Bundle pushGeoPoint(GeoPoint p) {
		Bundle bundle = new Bundle();
		bundle.putInt("lat", p.getLatitudeE6());
		bundle.putInt("long", p.getLongitudeE6());

		return bundle;
	}

	/**
	 * Convenience method for unpacking a GeoPoint from a android.os.Bundle bundle must be
	 * packed according to local standards.
	 * 
	 * @param bundle
	 * @return GeoPoint
	 */
	public static GeoPoint popGeoPoint(Bundle bundle) {
		GeoPoint p = new GeoPoint(bundle.getInt("lat"), bundle.getInt("long"));

		return p;
	}

	/**
	 * Returns whether the bundle contains a properly packaged GeoPoint
	 * according to local standards.
	 * 
	 * @param b
	 * @return
	 */
	public static boolean bundleHasGeoPoint(Bundle b) {
		return b.containsKey("lat") && b.containsKey("long");
	}
}
src/nu/placebo/whatsup/network/GeoLocationsRetrieve.java
public class GeoLocationsRetrieve extends
		AbstractNetworkOperation<List<GeoLocation>> {

	private double latitudeA;
	private double longitudeA;
	private double latitudeB;
	private double longitudeB;
	private boolean hasErrors;

	public GeoLocationsRetrieve(double latitudeA, double longitudeA,
			double latitudeB, double longitudeB) {
		this.latitudeA = latitudeA;
		this.longitudeA = longitudeA;
		this.latitudeB = latitudeB;
		this.longitudeB = longitudeB;
	}

	public GeoLocationsRetrieve(double[] area) {
		this.latitudeA = area[0];
		this.longitudeA = area[1];
		this.latitudeB = area[2];
		this.longitudeB = area[3];
	}

	public OperationResult<List<GeoLocation>> execute() {
		this.hasErrors = true;
		HttpResponse response = NetworkCalls
				.performGetRequest(Constants.API_URL + "nearby/"
						+ this.latitudeA + "," + this.longitudeA + ","
						+ this.latitudeB + "," + this.longitudeB + ".json");
		ResponseHandler<String> handler = new BasicResponseHandler();
		String result = null;
		try {
			result = handler.handleResponse(response);
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		List<GeoLocation> geoLocations = this.parse(result);

		if (response != null) {
			if(hasErrors) {
				geoLocations = null;
			}
			return new OperationResult<List<GeoLocation>>(
					this.hasErrors, response.getStatusLine().getStatusCode(),
					response.getStatusLine().getReasonPhrase(), geoLocations);
		} else {
			return new OperationResult<List<GeoLocation>>(
					hasErrors, 0, "Problems with the network", null);
		}

	}

	private List<GeoLocation> parse(String result) {
		List<GeoLocation> geoLocations = new ArrayList<GeoLocation>();
		if (result != null) {
			try {
				JSONArray json = new JSONArray(result);
				for (int i = 0; i < json.length(); i++) {
					JSONObject j = json.getJSONObject(i);
					geoLocations.add(new GeoLocation(j));
				}
				this.hasErrors = false;
			} catch (JSONException e) {
				e.printStackTrace();
			}
		}
		return geoLocations;
	}
}
src/nu/placebo/whatsup/network/NetworkCalls.java
public class NetworkCalls {

	private static HttpClient client = getHttpClient();
	private static boolean testing;

	public static HttpResponse performGetRequest(String query) {
		HttpGet request = new HttpGet(query);
		HttpResponse response = null;
		try {
			response = execute(request);
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return response;
	}

	private static HttpClient getHttpClient() {
		return AndroidHttpClient.newInstance("");
	}

	public static HttpResponse performPostRequest(String query,
			List<NameValuePair> body, SessionInfo sessionInfo) {
		HttpPost request = new HttpPost(query);

		HttpResponse response = null;
		try {
			if (body != null) {
				AbstractHttpEntity ent = new UrlEncodedFormEntity(body,
						HTTP.UTF_8);
				request.setEntity(ent);
			}
			if (sessionInfo != null) {
				request.addHeader(new BasicHeader("Cookie", sessionInfo
						.getSessionName() + "=" + sessionInfo.getSessionId()));
			}
			response = execute(request);
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return response;
	}

	private static HttpResponse execute(HttpUriRequest request)
			throws ClientProtocolException, IOException {
		if(!testing) {
			return client.execute(request);
		} else {
			return getHttpClient().execute(request);
		}
	}
	public static void setTesting(boolean b) {
		testing = b;
	}
}
src/nu/placebo/whatsup/model/GeoLocation.java
public class GeoLocation {
	private GeoPoint gp;
	private String title;
	private int id;

	public GeoLocation(int id, int microLat, int microLong, String title) {
		this.gp = new GeoPoint(microLat, microLong);
		this.title = title;
		this.id = id;
	}

	public GeoLocation(GeoLocation gl) {
		this.gp = gl.gp;
		this.title = gl.title;
		this.id = gl.id;
	}

	public GeoLocation(int id, double latitude, double longitude, String title) {
		this(id, (int) (latitude * 1000000 + 0.5),
				(int) (longitude * 1000000 + 0.5), title);

	}

	public GeoLocation(JSONObject j) throws JSONException {
		this(j.getInt("nid"), j.getDouble("latitude"),
				j.getDouble("longitude"), j.getString("title"));
	}

	/**
	 * @return the id
	 */
	public int getId() {
		return id;
	}

	/**
	 * @return the location
	 */
	public GeoPoint getLocation() {
		return gp;
	}

	/**
	 * @param gp
	 *            the gp to set
	 */
	public void setLocation(GeoPoint gp) {
		this.gp = gp;
	}

	/**
	 * @return the title
	 */
	public String getTitle() {
		return title;
	}

	/**
	 * @param title
	 *            the title to set
	 */
	public void setTitle(String title) {
		this.title = title;
	}
	@Override
	public boolean equals(Object o) {
		if(o != null && o instanceof GeoLocation) {
			GeoLocation other = (GeoLocation) o;
			return this.getId() == other.getId() &&
				   this.getTitle().equals(other.getTitle()) &&
				   this.getLocation().equals(other.getLocation());
		}
		return false;
	}
	
	@Override
	public int hashCode() {
		int result = 0;
		result += gp.hashCode();
		result += id;
		result += title.hashCode();
		return result;
	}
}
src/nu/placebo/whatsup/network/NetworkTask.java
public class NetworkTask<T> extends
		AsyncTask<NetworkOperation<T>, NetworkOperation<T>> {

	@Override
	protected NetworkOperation<T> doInBackground(NetworkOperation<T> o) {
		o.setOperationResult(o.execute());
		return o;
	}

	@Override
	protected void onPostExecute(NetworkOperation<T> o) {
		o.notifyListeners(o.getResult());
	}

}
src/nu/placebo/whatsup/network/NetworkOperationListener.java
public interface NetworkOperationListener<T> {
	public void operationExcecuted(OperationResult<T> result);
}
src/nu/placebo/whatsup/model/ExtendedOverlayItem.java
public class ExtendedOverlayItem extends OverlayItem {
	
	private int id;
	
	public ExtendedOverlayItem(GeoLocation g) {
		super(g.getLocation(), g.getTitle(), "Rating: 0");
		id = g.getId();
	}

	public int getId() {
		return id;
	}
}
src/nu/placebo/whatsup/model/ReferencePoint.java
public class ReferencePoint {

	private final int id;
	private GeoPoint geoPoint;

	public GeoPoint getGeoPoint() {
		return geoPoint;
	}

	public ReferencePoint(ReferencePoint r) {
		this(r.getId(), r.getGeoPoint(), r.getName());
	}

	public void setGeoPoint(GeoPoint geoPoint) {
		this.geoPoint = geoPoint;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getId() {
		return id;
	}

	private String name;

	public ReferencePoint(int id, GeoPoint geoPoint, String name) {
		this.id = id;
		this.geoPoint = geoPoint;
		this.name = name;
	}

}


Question: package nu.placebo.whatsup.activity;
import java.util.List;
import nu.placebo.whatsup.R;
import nu.placebo.whatsup.constants.Constants;
import nu.placebo.whatsup.datahandling.DataProvider;
import nu.placebo.whatsup.model.ExtendedOverlayItem;
import nu.placebo.whatsup.model.GeoLocation;
import nu.placebo.whatsup.model.ReferencePoint;
import nu.placebo.whatsup.network.GeoLocationsRetrieve;
import nu.placebo.whatsup.network.NetworkCalls;
import nu.placebo.whatsup.network.NetworkOperationListener;
import nu.placebo.whatsup.network.NetworkTask;
import nu.placebo.whatsup.network.OperationResult;
import nu.placebo.whatsup.util.GeoPointUtil;
import android.content.Context;
import android.content.Intent;
import android.location.LocationManager;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
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;




/**
 * Activity that holds the map and control map actions. It's the "main"
 * activity.
 * 
 * @author Albin Bramstång
 */
public class MapViewActivity extends MapActivity implements OnClickListener,
		NetworkOperationListener<List<GeoLocation>> {

	private MapView mapView;
	private Marker marker;
	private Marker refPointMarker;
	private List<Overlay> overlays;
	private LocationManager locationManager;
	private DataProvider dataProvider;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

Answer: 		NetworkCalls.setTesting(false);