Android mapping with Hebrew or, using the osmDroid API with ease.

You are here

Contact

Israel Office

+972-52-838-7222

+972-52-430-5252

Europe office

+33-695-805-004

27.03.2011
Android mapping with Hebrew or, using the osmDroid API with ease.
submitted by: royi

Hello,
last week i had the honor of attending an Android developers meeting that was organized by the "Israeli cantina" (http://www.cantina.org.il/) and was sponsored by "Google".
During the mingling portion of the evening it became apparent that the only thing that was greater than the interest in creating Android mapping applications in hebrew is the difficulty in doing so, so in this post i would like to share a bit of my experience in doing just that.

First of all - i would like to emphasis that this tutorial uses the excellent API that is provided by the OSMDroid open source project (http://code.google.com/p/osmdroid/).
Second of all - all the code that is talked about in this guide is free, and is published on my gitHub page (https://github.com/royiby/OSMap), feel free to use it as you see fit.

Third - it is important to point out (thank you - yaniv hamou) that it is necessary that you either run this app on a device with an sdcard (or memory - like the nexus s) or an emulator "with an SD card".

Now, lets get started.

Step 1 - perquisites.
In order to use the OSMDroid API you have to download 4 files and place them in a folder (which i named assets) in your project, this would look like so:

now right click on the project, click properties , and choose the "Java Build Path" tab and you will see a window like this:

press on the add Jars button and locate the files in your project's assets folder (or wherever you put them) and it should look like this:

press o.k.

Step 2 - xml values.
Go to the res->values folder and create an xml file (i called mine renderers.xml), it looks like this:

<?xml version="1.0" encoding="utf-8"?>

OsmaRender
Mapnik
Cycle Map
OpenArialMap
OSM base layer
Topographic
Hills
Cloudmade (small tiles)
Cloudmade (Standard tiles)
Cloudmade (Alternative tiles)

Step 3 - resource proxy implementation.
Create a new class that extends the "DefaultResourceProxyImpl" that comes with the osmdroid-android.jar
this class should look somewhat like this:

package com.linnovate.osmap;

import org.andnav.osm.DefaultResourceProxyImpl;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;

public class ResourceProxyImpl extends DefaultResourceProxyImpl {

private final Context mContext; public ResourceProxyImpl(final Context pContext) { super(pContext); mContext = pContext; } @Override public String getString(string pResId) { switch(pResId) { case osmarender : return mContext.getString(R.string.osmarender); case mapnik : return mContext.getString(R.string.mapnik); case cyclemap : return mContext.getString(R.string.cyclemap); case openareal_sat : return mContext.getString(R.string.openareal_sat); case base : return mContext.getString(R.string.base); case topo : return mContext.getString(R.string.topo); case hills : return mContext.getString(R.string.hills); case cloudmade_small : return mContext.getString(R.string.cloudmade_small); case cloudmade_standard : return mContext.getString(R.string.cloudmade_standard); //case unknown : return mContext.getString(R.string.unknown); default : return super.getString(pResId); } } @Override public Bitmap getBitmap(bitmap pResId) { switch(pResId) { case center : return BitmapFactory.decodeResource(mContext.getResources(), R.drawable.center); case direction_arrow : return BitmapFactory.decodeResource(mContext.getResources(), R.drawable.direction_arrow); case marker_default : return BitmapFactory.decodeResource(mContext.getResources(), R.drawable.marker_default); case marker_default_focused_base : return BitmapFactory.decodeResource(mContext.getResources(), R.drawable.marker_default_focused_base); case navto_small : return BitmapFactory.decodeResource(mContext.getResources(), R.drawable.navto_small); case next : return BitmapFactory.decodeResource(mContext.getResources(), R.drawable.next); case person : return BitmapFactory.decodeResource(mContext.getResources(), R.drawable.person); case previous : return BitmapFactory.decodeResource(mContext.getResources(), R.drawable.previous); default : return super.getBitmap(pResId); } } @Override public Drawable getDrawable(bitmap pResId) { switch(pResId) { case center : return mContext.getResources().getDrawable(R.drawable.center); case direction_arrow : return mContext.getResources().getDrawable(R.drawable.direction_arrow); case marker_default : return mContext.getResources().getDrawable(R.drawable.marker_default); case marker_default_focused_base : return mContext.getResources().getDrawable(R.drawable.marker_default_focused_base); case navto_small : return mContext.getResources().getDrawable(R.drawable.navto_small); case next : return mContext.getResources().getDrawable(R.drawable.next); case person : return mContext.getResources().getDrawable(R.drawable.person); case previous : return mContext.getResources().getDrawable(R.drawable.previous); default : return super.getDrawable(pResId); } }

}

Step 4 - The activity.
Open your project's activity (i called mine Map):
when you are done it should look like this:

package com.linnovate.osmap;

import org.andnav.osm.ResourceProxy;
import org.andnav.osm.util.GeoPoint;
import org.andnav.osm.views.OpenStreetMapView;
import org.andnav.osm.views.overlay.MyLocationOverlay;
import org.andnav.osm.views.util.Mercator;
import org.andnav.osm.views.util.OpenStreetMapRendererInfo;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.Window;
import android.view.WindowManager;
import android.widget.RelativeLayout;
import android.widget.RelativeLayout.LayoutParams;

public class Map extends Activity
{
public OpenStreetMapView mOSMap;
public MyLocationOverlay mLocationOverlay;

@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //Capturing all of the screen (haahaaahaaaa!!!) requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); //create the layout that you will use. RelativeLayout mLayout = new RelativeLayout(this); //create the map view that you will use. mOSMap = new OpenStreetMapView(this.getApplicationContext(), OpenStreetMapRendererInfo.values()[OpenStreetMapRendererInfo.MAPNIK.ordinal()]); //set built in zoom handles. mOSMap.setBuiltInZoomControls(true); //set multi-touch to true. mOSMap.setMultiTouchControls(true); //init your resource proxy (the file you created earlier). ResourceProxy mResourceProxy = new ResourceProxyImpl(getApplicationContext()); //create a layer - i created a location layer so that it will track the device's location. mLocationOverlay = new MyLocationOverlay(this.getBaseContext(), mOSMap, mResourceProxy); //add the layer you created to the map's layers. mOSMap.getOverlays().add(mLocationOverlay); //add the map to the layout while telling it to grab the whole screen. mLayout.addView(mOSMap, new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT)); //set the layout you created as the content view (what is visible since the creation of the activity). this.setContentView(mLayout); //set zoom (the number was chosen randomlly to get you acquainted with this feature). mOSMap.getController().setZoom(17); //set center of map to your location(or to 32.000000,35.000000 if the gps isn't on or functioning). setMapCenter(mLocationOverlay.getMyLocation()); } public void setMapCenter(GeoPoint geoPoint) { final org.andnav.osm.util.Point p; if(geoPoint != null) p = Mercator.projectGeoPoint(geoPoint, this.getPixelZoomLevel(), null); else p = Mercator.projectGeoPoint(new GeoPoint(32.000000,35.000000), this.getPixelZoomLevel(), null); final int worldSize_2 = this.getWorldSizePx()/2; mOSMap.scrollTo(p.x - worldSize_2, p.y - worldSize_2); } int getWorldSizePx() { return (1 << getPixelZoomLevel()); } /** * Get the equivalent zoom level on pixel scale */ int getPixelZoomLevel() { return mOSMap.getZoomLevel() + mOSMap.getRenderer().MAPTILE_ZOOM; } @Override public void onPause() { //this feature is turned off when the activity is paused to save battery life. mLocationOverlay.disableMyLocation(); super.onPause(); } public void onResume() { super.onResume(); mOSMap.setRenderer(OpenStreetMapRendererInfo.values()[OpenStreetMapRendererInfo.MAPNIK.ordinal()]); mLocationOverlay.enableMyLocation(); mLocationOverlay.followLocation(true); } @Override public void onRestart() { super.onRestart(); } @Override public void onStop() { super.onStop(); } @Override public void onDestroy() { super.onDestroy(); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { //Handle the back button if (keyCode == KeyEvent.KEYCODE_BACK) { //Ask the user if they want to quit new AlertDialog.Builder(this) .setIcon(android.R.drawable.ic_dialog_alert) .setTitle("Exit") .setMessage("Are you sure you want to leave?") .setNegativeButton(android.R.string.cancel, null) .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which){ // Exit the activity Map.this.finish(); } }) .show(); // Say that we've consumed the event return true; } return super.onKeyDown(keyCode, event); }

}

i tried to comment on every line to make its functionality very obvious, i hope i was successful.

Step 5 - The Manifest.
Open your Manifest file and add 4 permissions to it, like so:






*it is important to point out (thank you - yaniv hamou) that the permission that refers to extenal storage means that it is necessary that you either run this app on a device with an sdcard (or memory - like the nexus s) or an emulator "with an SD card".

Step 6 - enjoy!
Now, you are finally ready to run the application, when i did it looked like this (see if you can find where i am :).


Want to create an overlay for fixed stations?
Than check out the next tutorial here.

blogs