Poor Man's GPS
This post is written by: Dhaval Motghare (http://www.dhavalmotghare.com)
This is regarding some interesting piece of code I found on the Internet. As a requirement for one of my work projects I had to develop a location aware application for a blackberry device. As always you need a GPS built in for the same. You also have a option of using triangulation based on cell ID and tower ID if the network carrier provides you with such a information, but generally it is not available or you have to pay for it. But now you have a third option “Google”.
What google has done is as a requirment for its maps application for handheld devices it has created a huge database of cell ID, tower ID with a corresponding mapping with latitude and longitude. As a consequence if you can now get cell ID and tower ID for a particular device you could locate yourself without a GPS or a need to pay for the service if your carrier provides it.
How to do this? Well this post helped me in figuring this out. As you could see the post contains a way to fetch a lat/long values from an exposed google web service. All you need to do is somehow get cell ID and tower ID for your device. Java ME doesn’t have a specific API available for doing the same you could on some devices get the cell ID and tower ID by querying through the System.getProperty() method with a platform specific key.
For example on Nokia you could use
Series 40 3rd Edition, FP1 (or newer):
System.getProperty(“Cell-ID”)
S60 3rd Edition, FP2 (or newer):
System.getProperty(“com.nokia.mid.cellid”)
If the platform in question is a blackberry device it has a well documented API for getting the cell information. The following code would tell you how to go about it.
//#ifdef BLACKBERRY_8300try {Class.forName("net.rim.device.api.system.GPRSInfo");Class.forName("net.rim.device.api.system.GPRSInfo.GPRSCellInfo");} catch (Exception e) {e.printStackTrace();return false;}try {deviceInfoObject.setCellID(GPRSInfo.getCellInfo().getCellId());deviceInfoObject.setARFCN(GPRSInfo.getCellInfo().getARFCN());deviceInfoObject.setBSIC(GPRSInfo.getCellInfo().getBSIC());deviceInfoObject.setLAC(GPRSInfo.getCellInfo().getLAC());deviceInfoObject.setRAC(GPRSInfo.getCellInfo().getRAC());deviceInfoObject.setGPRSState(GPRSInfo.getGPRSState());deviceInfoObject.setMCC(GPRSInfo.getCellInfo().getMCC());deviceInfoObject.setMNC(GPRSInfo.getCellInfo().getMNC());} catch (Exception e) {e.printStackTrace();return false;}return true;
//#endif
After you have acquired the device info you could fetch lat/long values using the exposed google service. You could find the following code helpful which I ported to J2ME from the android specific code which could be found in the post I mentioned above.
public boolean queryForCoordinates(DeviceInfo deviceInfo) {
String baseURL = "http://www.google.com/glm/mmap";// Setup the connectionHttpConnection httpConnection = null;OutputStream outputStream = null;DataInputStream inputStream = null;
try {
httpConnection = openConnection(baseURL);byte[] pd;if(deviceInfo.getCellID() <= 0 || deviceInfo.getLAC() <= 0)pd = PostData(0, 0, 3105, 20601, false);elsepd = PostData(deviceInfo.getMCC(), deviceInfo.getMNC(), deviceInfo.getLAC(), deviceInfo.getCellID(), false);
handler.processRequestHeaderForCoordinates(httpConnection);
httpConnection.setRequestProperty("content-length", pd.length + "");outputStream = httpConnection.openOutputStream();outputStream.write(pd);outputStream.close();
DataInputStream dis = httpConnection.openDataInputStream();
// Read some prior datadis.readShort();dis.readByte();// Read the error-codeint errorCode = dis.readInt();if (errorCode == 0) {double lat = (double) dis.readInt() / 1000000D;double lng = (double) dis.readInt() / 1000000D;// Read the rest of the datadis.readInt();dis.readInt();dis.readUTF();
deviceInfo.setLatitude(lat);deviceInfo.setLongitude(lng);
System.out.println("Lattitude --" + lat);System.out.println("Longitude --" + lng);
} else {/* If the return code was not* valid or indicated an error,* we display a Sorry-Notification */return false;}return true;} catch (Exception e) {e.printStackTrace();return false;} finally {closeConnection(httpConnection, outputStream, inputStream);}
}
private byte[] PostData(int MCC, int MNC, int LAC, int CID, boolean shortCID) {/* The shortCID parameter follows heuristic experiences:* Sometimes UMTS CIDs are build up from the original GSM CID (lower 4 hex digits)* and the RNC-ID left shifted into the upper 4 digits.*/byte[] pd = new byte[]{0x00, 0x0e,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x1b,0x00, 0x00, 0x00, 0x00, // Offset 0x110x00, 0x00, 0x00, 0x00, // Offset 0x150x00, 0x00, 0x00, 0x00, // Offset 0x190x00, 0x00,0x00, 0x00, 0x00, 0x00, // Offset 0x1f0x00, 0x00, 0x00, 0x00, // Offset 0x230x00, 0x00, 0x00, 0x00, // Offset 0x270x00, 0x00, 0x00, 0x00, // Offset 0x2b(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,0x00, 0x00, 0x00, 0x00};
boolean isUMTSCell = ((long) CID > 65535);
if (isUMTSCell) {System.out.println("UMTS CID. {0} " + (shortCID ? "Using short CID to resolve." : ""));} else {System.out.println("GSM CID given.");}if (shortCID) {CID &= 0xFFFF;









