×
Namespaces

Variants
Actions
(Difference between revisions)

How to display an Address or a Point of Interest on a Map with Java ME

From Nokia Developer Wiki
Jump to: navigation, search
skalogir (Talk | contribs)
(Skalogir -)
 
skalogir (Talk | contribs)
(Skalogir -)
Line 5: Line 5:
  
 
==Introduction==
 
==Introduction==
The example described in this article includes the following features:
 
 
* Retrieval of the geographic coordinates for a given address or a place
 
* Retrieval of static images with given custom size, format and zoom level
 
* Zooming in and out functionality
 
 
<!-- The line bellow has been commented out because the demo throws an Exception after selecting "Search"-->
 
<!-- To see a live sample of this API, you can check here: [http://www.jappit.com/blog/j2me-online-emulator?midlet=google_maps Java ME Google Maps API sample MIDlet] -->
 
 
==Terms of Service==
 
{{Note|Google's Static Maps API no longer requires a Google Maps API key. However if you are not a Google Maps API Premier user, you should not use the code on this page outside a web-based application according to the Google Maps API Terms of Service [http://code.google.com/apis/maps/terms.html Terms and Conditions] (section 10.1.1(h)), unless
 
 
(i) your platform does not have a web browser or
 
<br />
 
(ii) your platform does have a web browser, but you provide a link that shows the location concerned either in the Google Maps native application (if your platform has one) or on the Google Maps website.
 
 
Also for non Premier users there is a limitation of 1000 unique (different) image requests per viewer per day.}}
 
  
 
==Disabling the On Screen Keypad==
 
==Disabling the On Screen Keypad==
Line 31: Line 14:
 
| '''Nokia-MIDlet-On-Screen-Keypad: no'''
 
| '''Nokia-MIDlet-On-Screen-Keypad: no'''
 
|}
 
|}
 
==  Comparison of Static Maps Rendering Services ==
 
 
There are several consideration when using a Static Maps Rendering Service, including how detailed the map coverage is for the location in question, how large the generated image will be, and therefore how much data traffic and delay will be generated when contacting the Service and downloading the image. The balance between keeping the image's quality high while maintaining the image's size low is also something to be considered.
 
 
The table below compares three different Maps Rendering Services:
 
 
{| class="wikitable"
 
|-
 
! Google's Static Maps API !!  Nokia's Map Image API !! Open Street Maps
 
|-
 
|  [[File:Googlesgreenwich.jpg‎]] ||  [[File:greenwich20.jpg]]|| [[File:Openstreetmap_greenwich.png‎]]
 
|-
 
| file size = 8 KB  ||  file size = 4KB|| file size: 47 KB
 
|}
 
 
{{Note|If you want to do anything more than just display a  '''single  map image''' (e.g adding panning to your app), you will be better off using  an integrated "dynamic" mapping Java ME library such as
 
[http://projects.developer.nokia.com/LBSPJME/wiki Nokia's Map API for Java ME], at the cost of including an extra library jar file (approx 151 KB) as part of your
 
app download. There is a significant reduction in required network traffic within the first couple of 200x200 pixel images due to the use of map tiling and caching.}}
 
 
==Source code: GoogleMaps class==
 
<code java>
 
import java.io.ByteArrayOutputStream;
 
import java.io.DataOutputStream;
 
import java.io.IOException;
 
import java.io.InputStream;
 
import java.util.Vector;
 
import javax.microedition.io.Connector;
 
import javax.microedition.io.HttpConnection;
 
import javax.microedition.lcdui.Image;
 
 
public class GoogleMaps {
 
    private static final String URL_UNRESERVED = 
 
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + 
 
        "abcdefghijklmnopqrstuvwxyz" +
 
        "0123456789-_.~";
 
    private static final char[] HEX = "0123456789ABCDEF".toCharArray();
 
 
    // these 2 properties will be used with map scrolling methods. You can remove them if not needed
 
    public static final int offset = 268435456;
 
    public static final double radius = offset / Math.PI;
 
 
    public GoogleMaps() { 
 
    }
 
 
    public double[] geocodeAddress(String address) throws Exception {
 
        byte[] res = loadHttpFile(getGeocodeUrl(address));
 
        String[] data = split(new String(res), ',');
 
 
        if (!data[0].equals("200")) {
 
            int errorCode = Integer.parseInt(data[0]);
 
            throw new Exception("Google Maps Exception: " + getGeocodeError(errorCode));
 
        }
 
 
        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 IOException {
 
        byte[] imageData = loadHttpFile(getMapUrl(width, height, lng, lat, zoom, format));
 
 
        return Image.createImage(imageData, 0, imageData.length);
 
    }
 
 
    private static 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 620:
 
            return "Too many queries";
 
        default:
 
            return "Generic error";
 
        }
 
    }
 
 
    private String getGeocodeUrl(String address) {
 
        return "http://maps.google.com/maps/geo?q=" + urlEncode(address) + "&output=csv";
 
    }
 
 
    private 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 ;
 
    }
 
 
    private static String urlEncode(String str) {
 
        StringBuffer buf = new StringBuffer();
 
        byte[] bytes = null;
 
        try {
 
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
 
            DataOutputStream dos = new DataOutputStream(bos);
 
            dos.writeUTF(str);
 
            bytes = bos.toByteArray();
 
        } catch (IOException e) {
 
            // ignore
 
        }
 
        for (int i = 2; i < bytes.length; i++) {
 
            byte b = bytes[i];
 
            if (URL_UNRESERVED.indexOf(b) >= 0) {
 
                buf.append((char) b);
 
            } else {
 
                buf.append('%').append(HEX[(b >> 4) & 0x0f]).append(HEX[b & 0x0f]);
 
            }
 
        }
 
        return buf.toString();
 
    }
 
 
    private static byte[] loadHttpFile(String url) throws IOException {
 
        byte[] byteBuffer;
 
 
        HttpConnection hc = (HttpConnection) Connector.open(url);
 
        try {
 
            hc.setRequestMethod(HttpConnection.GET);
 
            InputStream is = hc.openInputStream();
 
            try {
 
                int len = (int) hc.getLength();
 
                if (len > 0) {
 
                    byteBuffer = new byte[len];
 
                    int done = 0;
 
                    while (done < len) {
 
                        done += is.read(byteBuffer, done, len - done);
 
                    }
 
                } else {
 
                    ByteArrayOutputStream bos = new ByteArrayOutputStream();
 
                    byte[] buffer = new byte[512];
 
                    int count;
 
                    while ( (count = is.read(buffer)) >= 0 ) {
 
                        bos.write(buffer, 0, count);
 
                    }
 
                    byteBuffer = bos.toByteArray();
 
                }
 
            } finally {
 
                is.close();
 
            }
 
        } finally {
 
            hc.close();
 
        }
 
 
        return byteBuffer;
 
    }
 
 
    private static String[] split(String s, int chr) {
 
        Vector res = new Vector();
 
 
        int curr;
 
        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;
 
    }
 
}
 
</code>
 
 
==Addition of a map scrolling functionality==
 
 
This example can be extended to include scrolling, i.e. the ability to move around the current map point, by catching the user's input and by retrieving new images. For that, the new center for the static image should be calculated. The following '''adjust()''' method returns the latitude and longitude values for the new map's center. The method requires the following arguments:
 
 
* the current center's '''latitude''' and '''longitude''' coordinates
 
* the '''deltaX''' and '''deltaY''' values, which represent the deviation in pixels, of the new map center from the current one
 
* the map's '''zoom''' level
 
<br/>
 
Original code, in JavaScript, can also be found [http://home.provide.net/~bratliff/adjust.js here]<br/><br/>
 
{{Note| In order to use the methods described below, the '''MicroFloat''' library should be included in the project. The library is available here: [http://www.dclausen.net/projects/microfloat/ MicroFloat website]}}
 
 
{{Note|Instead of coding the scrolling functionality, as an alternative solution one could use '''Nokia's Maps API for Java ME''', where this is provided by default as a MapCanvas. The API is provided as external library and it should therefore be included in the project. The library is available [http://projects.developer.nokia.com/LBSPJME/wiki here].}}
 
 
<code java>
 
public double[] adjust(double lat, double lng, int deltaX, int deltaY, int z)
 
{
 
return new double[]{
 
XToL(LToX(lng) + (deltaX<<(21-z))),
 
YToL(LToY(lat) + (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;
 
}
 
</code>
 
 
==Description of example's main calls==
 
 
The GoogleMaps class, contains the methods for geocoding addresses and map image retrievals. It can be instantiated as follows:
 
<code java>
 
GoogleMaps gMap = new GoogleMaps();
 
</code>
 
 
In order to geocode an address or a point of interest, the geocodeAddress() method of the GoogleMaps class should be called as follows:
 
<code java>
 
double[] lanLng = gMap.geocodeAddress("Eiffel tower");
 
</code>
 
 
In order to retrieve a map image that corresponds to a given point, we have to specify the image's width and height, the point's latitude and longitude values, as well as the zoom level and the image type:
 
<code java>
 
Image map = gMap.retrieveStaticImage(width, height, lanLng[0], lanLng[1], 14, "png32");
 
</code>
 
 
Note that the zoom level can be any value from 0 to 21.
 
  
 
==Resources==
 
==Resources==
  
The example's source code can be downloaded from here: [[File:GoogleMapsMIDletSource.zip]]
+
The example's source code can be downloaded from here: [[File:NokiaMapsShowPOIonMapSource.zip]]
  
The example's installation binary files can be downloaded from here: [[File:GoogleMapsMIDletBinaries.zip]]
+
The example's installation binary files can be downloaded from here: [[File:NokiaMapsShowPOIonMapBinaries.zip]]
  
 
==See also==
 
==See also==
Line 302: Line 32:
  
 
{{ArticleMetaData
 
{{ArticleMetaData
|sourcecode=[[Media:GoogleMapsMIDletSource.zip]]
+
|sourcecode=[[Media:NokiaMapsShowPOIonMapSource.zip]]
[[Media:GoogleMapsMIDletBinaries.zip]]
+
[[Media:NokiaMapsShowPOIonMapBinaries.zip]]
 
|installfile=
 
|installfile=
|devices=Nokia X3-02, Nokia 6210N, Nokia 6233, Nokia 701
+
|devices=Nokia X3-02, Nokia 6210N, Nokia 6700classic, Nokia 701
 
|sdk=[http://www.developer.nokia.com/Develop/Java/ Nokia SDK 1.0 for Java]
 
|sdk=[http://www.developer.nokia.com/Develop/Java/ Nokia SDK 1.0 for Java]
 
|platform=Series 40, Symbian
 
|platform=Series 40, Symbian
|devicecompatability= since Series 40 6th Edition, since Symbian S60 3rd Edition
+
|devicecompatability= MIDP2.0/CLDC 1.1
 
|signing=
 
|signing=
 
|capabilities=<!-- Capabilities required by the article/code example (e.g. Location, NetworkServices. -->
 
|capabilities=<!-- Capabilities required by the article/code example (e.g. Location, NetworkServices. -->
|keywords=Google Static Maps API, Image, Coordinates, Search Address or POI on a Map, GeoLocation
+
|keywords=Nokia Maps API for Java ME, Image, Coordinates, Search Address or Point of Interest on a Map, GeoLocation
 
|id= <!-- Article Id (Knowledge base articles only) -->
 
|id= <!-- Article Id (Knowledge base articles only) -->
|creationdate=20111128
+
|creationdate=20120113
|author=[[User:jappit]]
+
|author=[[User:skalogir]]
 
|review-by=[[User:skalogir]]
 
|review-by=[[User:skalogir]]
|review-timestamp=20120111
+
|review-timestamp=20120113
 
}}
 
}}
 
 
<!-- translations -->
 
[[ja:Google Maps API in Java ME(日本語)]]
 

Revision as of 16:07, 13 January 2012

This article describes how to search for an address or a point of interest and display it on the Map. It uses Nokia's Map API for Java ME for the translation of the search string into valid coordinates and for the retrieval of the relevant map image.

Sydneypoi.pngSydneyshow.png

Contents

Introduction

Disabling the On Screen Keypad

In order to take advantage of the entire screen, the following line should be added to the application's file descriptor (jad file):

Nokia-MIDlet-On-Screen-Keypad: no

Resources

The example's source code can be downloaded from here: File:NokiaMapsShowPOIonMapSource.zip

The example's installation binary files can be downloaded from here: File:NokiaMapsShowPOIonMapBinaries.zip

See also

Article Metadata
Code ExampleTested with
Devices(s): Nokia X3-02, Nokia 6210N, Nokia 6700classic, Nokia 701
Compatibility
Device(s): MIDP2.0/CLDC 1.1
Article
Keywords: Nokia Maps API for Java ME, Image, Coordinates, Search Address or Point of Interest on a Map, GeoLocation
Created: skalogir (13 Jan 2012)
Reviewed: skalogir (13 Jan 2012)
Last edited: skalogir (13 Jan 2012)
183 page views in the last 30 days.
×