Update … IP-Geolocator has been ported as a Google Chrome extension…you may find it here
While most of 2010 was dominated by starting a new job, getting married, and experimenting with Amazons EC2 cloud service … I was able to complete/publish my first android application over the winter holiday. The application is a simple IP – Geolocation service that quickly geolocates an IP address using Google Maps and the Maxmind GeoLite City database. In a nutshell, requests are processed via an Amazon EC2 powered webservice that hosts the GeoLite City database and responses are displayed on the requesters device using Google Maps. The services GeoLite City database has an accuracy of up to 99.5% on a country level and 79% on a city level and uses Open Data License which requires me to note that “This product includes GeoLite data created by MaxMind, available from http://maxmind.com” . Lastly, for those interested in more accurate geo-location, please be sure to visit Maxmind.
Here is a screen shot:
You can find the application in the Android Market by searching for “IP Geo” or download directly via QR:
package com.ericonjava;
public interface Caller {
public void postRequestHandler(String result);
}
package com.ericonjava;
import java.io.InputStream;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpConnectionParams;
import android.os.AsyncTask;
import android.util.Log;
public class GeoIpTranslateTask extends AsyncTask<String, Void, String> {
private Caller caller;
public GeoIpTranslateTask(Caller caller){
this.caller = caller;
}
protected String doInBackground(String... ip) {
return callGeoIpTranslationService(ip[0]);
}
protected void onPostExecute(String result) {
caller.postRequestHandler(result);
}
private String callGeoIpTranslationService(String ip){
String return_str = "";
try{
HttpClient hc = new DefaultHttpClient();
HttpGet get = new HttpGet("SERVICE"+ip);
HttpConnectionParams.setConnectionTimeout(hc.getParams(), 15000);
HttpResponse rp = hc.execute(get);
if(rp.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
InputStream is = rp.getEntity().getContent();
byte[] readBytes =new byte[512];
is.read(readBytes);
return_str = new String(readBytes);
//Log.v("MYTAG", "response string="+return_str);
}
else{
return_str = "ERROR- The request failed with status code"+ rp.getStatusLine().getStatusCode();
}
}catch(Exception e){
return_str = "ERROR- The request to the GEO-IP server failed. Please ensure that a data connection is availible";
return return_str;
}
return return_str;
}
}
package com.ericonjava;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.json.JSONException;
import org.json.JSONObject;
import com.ericonjava.R;
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;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class MainView extends MapActivity implements Caller {
//Regex from http://stackoverflow.com/questions/106179/regular-expression-to-match-hostname-or-ip-address
private String ValidIpAddressRegex = "^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$";
private Pattern pattern;
private Matcher matcher;
private Button aButton;
private MapView mapView;
private MainView ref;
private String ipaddress;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ref = this;
setContentView(R.layout.main);
pattern = Pattern.compile(ValidIpAddressRegex);
mapView = (MapView) findViewById(R.id.mapview);
mapView.setBuiltInZoomControls(true);
aButton = (Button) findViewById(R.id.ok);
aButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
EditText stxt = (EditText) findViewById(R.id.entry);
ipaddress = stxt.getText().toString().trim();
if(validateIPString(ipaddress)){
aButton.setEnabled(false);
new GeoIpTranslateTask(ref).execute(ipaddress);
}else{
Toast toast = Toast.makeText(getApplicationContext(), "Please enter a valid IP address", 30);
toast.show();
}
} });
}
public boolean validateIPString(final String ip){
matcher = pattern.matcher(ip);
return matcher.matches();
}
private GeoPoint getPoint(double lat, double lon) {
//GeoPoint gp = new GeoPoint((int)(lat * 1E6), (int)(lng * 1E6));
return(new GeoPoint((int)(lat*1000000.0),(int)(lon*1000000.0)));
}
@Override
protected boolean isRouteDisplayed() {
return false;
}
public void postRequestHandler(String result){
aButton.setEnabled(true);
JSONObject json_obj;
try{
json_obj = new JSONObject(result);
String slat=json_obj.getString("latitude");
String slong=json_obj.getString("longitude");
String countryname=json_obj.getString("country_name");
String city=json_obj.getString("city");
String region=json_obj.getString("region");
double lat = Double.parseDouble(slat);
double lon = Double.parseDouble(slong);
GeoPoint gp = getPoint(lat,lon);
mapView.getController().setZoom(9);
mapView.getController().animateTo(gp);
List<Overlay> mapOverlays = mapView.getOverlays();
Drawable drawable = this.getResources().getDrawable(R.drawable.marker);
SitesOverlay itemizedoverlay = new SitesOverlay(drawable,getApplicationContext());
OverlayItem overlayitem = new OverlayItem(gp,ipaddress,ipaddress);
itemizedoverlay.addOverlay(overlayitem);
mapOverlays.add(itemizedoverlay);
TextView textView = (TextView) findViewById(R.id.display);
textView.setText("Longitude = "+ slat + " nLongitude = " +slong+" nCity = " +city+" nRegion = " +region+" nCountry = " +countryname);
textView.setHorizontalScrollBarEnabled(true);
Toast toast = Toast.makeText(getApplicationContext(), "Request has completed succesfully", 3);
toast.show();
} catch (JSONException e) {
Toast toast = Toast.makeText(getApplicationContext(),"Unable to process request...please try again", 10);
toast.show();
}
}
}
package com.ericonjava;
import java.util.ArrayList;
import java.util.List;
import com.google.android.maps.ItemizedOverlay;
import com.google.android.maps.MapView;
import com.google.android.maps.OverlayItem;
import android.app.AlertDialog;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.widget.Toast;
public class SitesOverlay extends ItemizedOverlay<OverlayItem> {
private Context mContext;
private List<OverlayItem> items=new ArrayList<OverlayItem>();
public SitesOverlay(Drawable defaultMarker,Context context) {
super(boundCenterBottom(defaultMarker));
mContext = context;;
}
@Override
protected OverlayItem createItem(int i) {
return(items.get(i));
}
@Override
public int size() {
return items.size();
}
@Override
public void draw(Canvas canvas, MapView mapView,boolean shadow) {
super.draw(canvas, mapView, shadow);
}
@Override
protected boolean onTap(int index) {
OverlayItem item = items.get(index);
Toast toast = Toast.makeText(mContext,item.getTitle(), 10);
toast.show();
return true;
}
public void addOverlay(OverlayItem overlay) {
items.add(overlay);
populate();
}
}
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:id="@+id/label"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Enter IP address here: (e.g. 25.36.88.111)"/>
<EditText
android:id="@+id/entry"
android:layout_width="225dip"
android:layout_height="wrap_content"
android:background="@android:drawable/editbox_background"
android:layout_below="@id/label"/>
<Button
android:id="@+id/ok"
android:layout_width="70dip"
android:layout_height="50dip"
android:layout_toRightOf="@id/entry"
android:layout_below="@id/label"
android:layout_marginLeft="10dip"
android:text="OK" />
<com.google.android.maps.MapView
android:id="@+id/mapview"
android:layout_marginTop="10dip"
android:layout_below="@id/ok"
android:layout_width="wrap_content"
android:layout_height="200dip"
android:clickable="true"
android:apiKey="0Pguc-Ti7nkyeaRXxqNZUOsJeyvYplrjGuL5mHg"
/>
<TextView
android:id="@+id/display"
android:layout_below="@id/mapview"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text=""/>
<TextView
android:id="@+id/disclaimer"
android:layout_alignParentBottom ="true"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:textSize="8px"
android:text="This product includes GeoLite data created by MaxMind, available from http://www.maxmind.com/."/>
</RelativeLayout>
Complete Project / Source code is posted on Github.
![]()

