Join Now
Quality Rating:
  • Currently 0.0 / 5
(0.0 / 5 - 0 votes cast)
Expertise Level:
  • Currently 0.0 / 5
(0.0 / 5 - 0 votes cast)

This page was last modified 18:55, 16 July 2008.

J2ME Google Maps API

From Forum Nokia Wiki

Here is a simple library to query Google Maps with the following features:

  • geocode addresses to their geographic coordinates
  • retrieve static images with given custom size, format and zoom

To see a live sample of this API, you can check here: Java ME Google Maps API sample MIDlet

Contents

Get your own Google Maps API Key

To use the following code, you should get your own Google Maps API Key. If you have not an API key, you can follow the instructions here: How to use Google Maps data in mobile applications

Use a Proxy server to access Google Map services

Note: this subject (proxy usage) is probably non necessary, still investigating it..
When you sign up to obtain a Google Maps API key, you enter the address that will be able to access Maps services with that key. For this reason, you should setup a Proxy server on that address that will receive HTTP requests from your mobile clients, forwarding them to Google Maps services, giving back Google responses.

In the code below, you should forward the following requests:

Source code: GoogleMaps class

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
 
import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;
import javax.microedition.lcdui.Image;
 
public class GoogleMaps
{
	String apiKey = null;
 
	//these 2 properties will be used with map scrolling methods. You can remove them if not needed
	int offset = 268435456;
	double radius = offset / Math.PI;
	
	public GoogleMaps(String apiKey)
	{
		this.apiKey = apiKey;
	}
	
	public double[] geocodeAddress(String address) throws Exception
	{
		byte[] res = loadHttpFile(getGeocodeUrl(address));
		
		String resString = new String(res, 0, res.length);
		
		String[] data = split(resString, ',');
		
		if(data[0].compareTo("200") != 0)
		{
			int errorCode = Integer.parseInt(data[0]);
			
			throw new Exception("Google Maps Exception: " + getGeocodeError(errorCode));
		}
		else
		{
			return new double[]{
				Double.parseDouble(data[2]),
				Double.parseDouble(data[3])
			};
		}
	}
	public Image retrieveStaticImage(int width, int height, double lat, double lng, int zoom, String format) throws Exception
	{
		byte[] imageData = loadHttpFile(getMapUrl(width, height, lng, lat, zoom, format));
		
		return Image.createImage(imageData, 0, imageData.length);
	}
	
	String getGeocodeError(int errorCode)
	{
		switch(errorCode)
		{
		case 400:
			return "Bad request";
		case 500:
			return "Server error";
		case 601:
			return "Missing query";
		case 602:
			return "Unknown address";
		case 603:
			return "Unavailable address";
		case 604:
			return "Unknown directions";
		case 610:
			return "Bad API key";
		case 620:
			return "Too many queries";
		default:
			return "Generic error";
		}
	}
	
	String getGeocodeUrl(String address)
	{
		return "http://maps.google.com/maps/geo?q=" + urlEncode(address) 
			+ "&output=csv&key=" + apiKey;
	}
	String getMapUrl(int width, int height, double lng, double lat, int zoom, String format)
	{
		return "http://maps.google.com/staticmap?center=" + 
			lat + "," + lng + "&format=" + format + "&zoom=" + zoom + "&size=" + 
			width + "x" + height + "&key=" + apiKey;
	}
	String urlEncode(String str)
	{
		StringBuffer buf = new StringBuffer();
		char c;
		for(int i = 0; i < str.length(); i++)
		{ 
			c = str.charAt(i);
			if ((c >= '0' && c <= '9')||
				(c >= 'A' && c <= 'Z')||
				(c >= 'a' && c <= 'z'))
			{
				buf.append(c);
			}
			else
			{
				buf.append("%").append(Integer.toHexString((int) str.charAt(i)));
			}
		} 
		return buf.toString();
	}
	byte[] loadHttpFile(String url) throws Exception
	{
		HttpConnection hc = null;
		
		InputStream is = null;                         
		
		byte[] byteBuffer = null;
		
		try
		{
			hc = (HttpConnection) Connector.open(url);
			
			hc.setRequestMethod(HttpConnection.GET);
	
			int ch;
	
			is = hc.openInputStream();
	
			int len = (int)hc.getLength();
			
			if(len > 0)
			{
				byteBuffer = new byte[len];
				
				is.read(byteBuffer);
			}
			else
			{
				ByteArrayOutputStream bos = new ByteArrayOutputStream();
				
				while ((ch = is.read()) != -1)
				{
					bos.write(ch);
				}
				byteBuffer = bos.toByteArray();
				
				bos.close();
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		finally
		{
			try
			{
				if(is != null)
					is.close();
				
				if(hc != null)
					hc.close();
			}
			catch(Exception e2)
			{
				e2.printStackTrace();
			}
		}
		return byteBuffer;
	}
	static String[] split(String s, int chr)
	{
		Vector res = new Vector();
		
		int curr = 0;
		int prev = 0;
		
		while((curr = s.indexOf(chr, prev)) >= 0)
		{
			res.addElement(s.substring(prev, curr));
			
			prev = curr + 1;
		}
		res.addElement(s.substring(prev));
		
		String[] splitted = new String[res.size()];
		
		res.copyInto(splitted);
		
		return splitted;
	}
}

Utility method for map scrolling

If you need to scroll your map, you'll need to calculate a new center for your static image. The following adjust() method will return the new map center latitude and longitude, accepting the following arguments:

  • the current center latitute and longitude coordinates
  • the deltaX and deltaY, in pixels, of new map center
  • the map zoom level


Original code, in JavaScript, is available here: http://www.polyarc.us/adjust.js

Note: to use the following methods, you must include in your project the MicroFloat library, available here: MicroFloat website

public double[] adjust(double lat, double lng, int deltaX, int deltaY, int z)
{
	return new double[]{
		XToL(LToX(lat) + (deltaX<<(21-z))),
		YToL(LToY(lng) + (deltaY<<(21-z)))
	};
}
double LToX(double x)
{
	return round(offset + radius * x * Math.PI / 180);
}
 
double LToY(double y)
{
	return round(
		offset - radius * 
		Double.longBitsToDouble(MicroDouble.log(
			Double.doubleToLongBits(
			(1 + Math.sin(y * Math.PI / 180))
			/
			(1 - Math.sin(y * Math.PI / 180))
			)
		)) / 2);
}
 
double XToL(double x)
{
	return ((round(x) - offset) / radius) * 180 / Math.PI;
}
 
double YToL(double y)
{
	return (Math.PI / 2 - 2 * Double.longBitsToDouble(
				MicroDouble.atan(
					MicroDouble.exp(Double.doubleToLongBits((round(y)-offset)/radius))
				)
			)) * 180 / Math.PI;
}
double round(double num)
{
	double floor = Math.floor(num);
	
	if(num - floor >= 0.5)
		return Math.ceil(num);
	else
		return floor;
}

Source code: sample usage

Image:J2me_google_maps.jpg
To use this class, you firstly instantiate it with your API key:

GoogleMaps gMap = new GoogleMaps("API_KEY");

To geocode an address, you can use the geocodeAddress() method:

double[] lanLng = gMap.geocodeAddress("Leicester Square, London");

To retrieve a map image:

Image map = gMap.retrieveStaticImage(320, 240, 51.510605, -0.130728, 8, "png32");
Related Discussions
Thread Thread Starter Forum Replies Last Post
Can I access the bluetooth with J2ME And MMS kokoadi Mobile Java General 1 2003-03-31 10:25
Screen saver using J2ME ksethumadhavan Mobile Java General 3 2005-08-04 14:30
How create a interface between a J2ME and a synthetizer ? mouldnadif Mobile Java Media (Graphics & Sounds) 1 2005-02-21 18:49
"Splinter cell" Collision Techniqe vishwas_dot_h Mobile Java Media (Graphics & Sounds) 5 2004-05-09 08:08
Newbie question saleem145 General Symbian C++ 1 2006-09-27 10:21
 
Powered by MediaWiki
     
     RDF Facets:
     
     
     qfnZtopicQUqfnTopicZjavaQ
     qfnZtypeQUqfnTypeZCommunityContentQ
     qfnZtypeQUqfnTypeZWebpageQ
     qfnZtypeQUqfnTypeZWikiContentQ
     qmarsZlanguageQUxhttpE3aE2fE2fswE2enokiaE2ecomE2flanguageE2d1E2fenX
     
    
            
            RDF Facets:
            
            
                        qfnZuserE5ftagQSxcellX
                        qfnZuserE5ftagQSxgsmX
                        qfnZuserE5ftagQSxidX