Mil2525c Sample

The purpose of this sample is to introduce you to the Military Symbology features in the API. For any Military Symbology apps you need a Symbol Dictionary and the default Message Types on your device in the following default location /<external-storage-directory>/ArcGIS/SymbolDictionary. This is where the MessageProcess class will look for the Symbol Dictionary resources. To use a custom path you need to use the MessageProcessor overloaded constructor which takes in a java.lang.String Symbol Dictionary path.

Sample Design

This sample illustrates the use of MessageProcessor class to process Military 2525c Symbology features whose definitions are stored locally on your device. The MessageProcessor class provides the capability to take a message received from an external source and convert it into a symbol which is displayed on a map in a GraphicsLayer. The MessageProcessor class requires a GroupLayer to be added to an initialized MapView.

The MessageProcessor constructor requires a DictionaryType which indicates the type of symbol dictionary is being used. The Message class encapsulates information from an incoming or outgoing message. Apart from a message ID all other properties in the message are held in name-value pairs.

This sample draws samples based on an XML file located in /res/raw/coa.xml. You can add any supported symbols to this file to add more complex symbols.

Provision your device

  1. The symbol dictionary resource files are included with your local SDK install at /resources/mil2525c.
  2. Create a folder on your device named /<external-storage-directory>/ArcGIS/SymbolDictionary. Please refer to the Android SDK adb tool for instructions on how to create folders on your device.
  3. Open up a command prompt and execute the adb shell command to start a remote shell on your target device.
  4. Navigate to your sdcard directory, cd /sdcard/.
  5. Create the ArcGIS directory, mkdir ArcGIS/SymbolDictionary.
  6. You should now have a directory similar on your target device, /mnt/sdcard/ArcGIS/SymbolDictionary. We will copy the contents of the resource into this directory.
  7. Exit the shell with the, exit command.
  8. While still in your command prompt, navigate to your local SDK install at /resources/mil2525c folder and execute the following command:

$ adb push mil2525c /sdcard/ArcGIS/SymbolDictionary

Sample Code


import java.util.List;

import org.xmlpull.v1.XmlPullParserException;

import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;

import com.esri.core.geometry.Geometry;
import com.esri.core.geometry.Point;
import com.esri.core.symbol.advanced.Message;
import com.esri.core.symbol.advanced.MessageGroupLayer;
import com.esri.core.symbol.advanced.MessageHelper;
import com.esri.core.symbol.advanced.MessageProcessor;
import com.esri.core.symbol.advanced.SymbolDictionary.DictionaryType;

public class MainActivity extends Activity {

	MapView mMapView;
	MessageProcessor mProcessor;

	private MessageGroupLayer messageGrLayer;

	protected void onCreate(Bundle savedInstanceState) {

		mMapView = (MapView) findViewById(;

		try {
			messageGrLayer = new MessageGroupLayer(DictionaryType.MIL2525C);
			mProcessor = messageGrLayer.getMessageProcessor();
		} catch (FileNotFoundException e1) {

		mMapView.setOnSingleTapListener(new OnSingleTapListener() {

			private static final long serialVersionUID = 1L;

			public void onSingleTap(float x, float y) {
				InputStream is = getResources().openRawResource(R.raw.symbols);
				// instantiate the parser
				Mil2525cMessageParser mil2525cParser = new Mil2525cMessageParser();
				List<GeoMessage> geoMessages = null;
				try {
					geoMessages = mil2525cParser.parse(is);

				} catch (XmlPullParserException e) {
				} catch (IOException e) {
				} finally { // make sure InputStream is closed after the app is
							// finished
					if (is != null) {
						try {
						} catch (IOException e) {

				for (GeoMessage geoMessage : geoMessages) {
					// Message creation
					Message message = new Message();

					message.setProperty("_Type", geoMessage.type);
					message.setProperty("_Action", geoMessage.action);
					Log.i("Test", "control point:" + geoMessage.controlpoints);
					message.setProperty("_WKID", geoMessage.wkid);
					message.setProperty("sic", geoMessage.sic);
					Log.i("Test", "sic: " + geoMessage.sic);


					Log.i("Test", String.valueOf(messageGrLayer.count()));


		mMapView.setOnLongPressListener(new OnLongPressListener() {
			private static final long serialVersionUID = 1L;

			public boolean onLongPress(float x, float y) {

				// get to the layer where the selected graphic is
				Layer[] layers = messageGrLayer.getLayers();
				for (Layer layer : layers) {
					if (layer instanceof GraphicsLayer) {
						GraphicsLayer gLayer = (GraphicsLayer) layer;
						int[] graphics = gLayer.getGraphicIDs(x, y, 50);
						if (graphics != null && graphics.length > 0) {
							Log.d("Test", "Graphic is found");
							// Create graphic
							Graphic graphic = gLayer.getGraphic(graphics[0]);
							Geometry geom = graphic.getGeometry();
							Point targetControlPnt = null;
							if (geom instanceof Point) {
								Point pnt = (Point) geom;
								Point screenPnt = mMapView.toScreenPoint(pnt);
								screenPnt = new Point(screenPnt.getX() + 50,
										screenPnt.getY() - 50);
								targetControlPnt = mMapView
								Log.d("Test", "x: " + targetControlPnt.getX()
										+ "; y: " + targetControlPnt.getY());

							Message message = mProcessor
							String controlPoints = (String) message
							Log.i("Test", "control point:" + controlPoints);
							if (targetControlPnt != null) {
										targetControlPnt.getX() + ","
												+ targetControlPnt.getY());
							message.setProperty("_Action", "update");


				return true;


	public boolean onCreateOptionsMenu(Menu menu) {

		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(, menu);
		return true;

	public boolean onOptionsItemSelected(MenuItem item) {
		// Handle action bar item clicks here. The action bar will
		// automatically handle clicks on the Home/Up button, so long
		// as you specify a parent activity in AndroidManifest.xml.
		int id = item.getItemId();
		if (id == {
			return true;
		return super.onOptionsItemSelected(item);


import java.util.ArrayList;
import java.util.List;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import android.util.Log;
import android.util.Xml;

public class Mil2525cMessageParser {

	// no namespace
	private static final String ns = null;

	public List<GeoMessage> parse(InputStream in)
			throws XmlPullParserException, IOException {
		try {
			// instantiate a parser, use an InputStream as input
			XmlPullParser parser = Xml.newPullParser();
			parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
			parser.setInput(in, null);
			// start the parsing process
			// invoke readFeed() method to extract and process data
			return readGeoMessages(parser);
		} finally {

	 * @param parser
	 * @return List containing the entries extracted from feed
	 * @throws XmlPullParserException
	 * @throws IOException
	private List<GeoMessage> readGeoMessages(XmlPullParser parser)
			throws XmlPullParserException, IOException {

		List<GeoMessage> geoMessages = new ArrayList<GeoMessage>();

		parser.require(XmlPullParser.START_TAG, ns, "geomessages");
		while ( != XmlPullParser.END_TAG) {
			String pName = parser.getName();
			// Start looking for the geomessage tag
			if (pName != null && pName.equals("geomessage")) {
			} else {
				Log.d("DEBUG", "TAG NAME = " + pName);

		return geoMessages;

	// Parses the contents of an geomessage.
	private GeoMessage readGeoMessage(XmlPullParser parser)
			throws XmlPullParserException, IOException {

		parser.require(XmlPullParser.START_TAG, ns, "geomessage");

		String name = null;
		String type = null;
		String action = null;
		String id = null;
		String controlpoints = null;
		String wkid = null;
		String sic = null;
		String uniquedesignation = null;

		while ( != XmlPullParser.END_TAG) {
			if (parser.getEventType() != XmlPullParser.START_TAG) {

			String pName = parser.getName();
			if (pName.equals("_name")) {
				name = readName(parser);
			} else if (pName.equals("_type")) {
				type = readType(parser);
			} else if (pName.equals("_action")) {
				action = readAction(parser);
			} else if (pName.equals("_id")) {
				id = readID(parser);
			} else if (pName.equals("_control_points")) {
				controlpoints = readControlPoints(parser);
			} else if (pName.equals("_wkid")) {
				wkid = readWkid(parser);
			} else if (pName.equals("sic")) {
				sic = readSic(parser);
			} else if (pName.equals("uniquedesignation")) {
				uniquedesignation = readUniqueDesignation(parser);

		return new GeoMessage(name, type, action, id, controlpoints, wkid, sic,

	private String readUniqueDesignation(XmlPullParser parser)
			throws IOException, XmlPullParserException {
		parser.require(XmlPullParser.START_TAG, ns, "uniquedesignation");
		String uniquedesignation = readText(parser);
		parser.require(XmlPullParser.END_TAG, ns, "uniquedesignation");

		return uniquedesignation;

	private String readSic(XmlPullParser parser) throws IOException,
			XmlPullParserException {
		parser.require(XmlPullParser.START_TAG, ns, "sic");
		String sic = readText(parser);
		parser.require(XmlPullParser.END_TAG, ns, "sic");

		return sic;

	private String readWkid(XmlPullParser parser) throws IOException,
			XmlPullParserException {
		parser.require(XmlPullParser.START_TAG, ns, "_wkid");
		String wkid = readText(parser);
		parser.require(XmlPullParser.END_TAG, ns, "_wkid");

		return wkid;

	private String readControlPoints(XmlPullParser parser) throws IOException,
			XmlPullParserException {
		parser.require(XmlPullParser.START_TAG, ns, "_control_points");
		String controlpoints = readText(parser);
		parser.require(XmlPullParser.END_TAG, ns, "_control_points");

		return controlpoints;

	private String readID(XmlPullParser parser) throws IOException,
			XmlPullParserException {
		parser.require(XmlPullParser.START_TAG, ns, "_id");
		String id = readText(parser);
		parser.require(XmlPullParser.END_TAG, ns, "_id");

		return id;

	private String readAction(XmlPullParser parser) throws IOException,
			XmlPullParserException {
		parser.require(XmlPullParser.START_TAG, ns, "_action");
		String action = readText(parser);
		parser.require(XmlPullParser.END_TAG, ns, "_action");

		return action;

	private String readType(XmlPullParser parser) throws IOException,
			XmlPullParserException {
		parser.require(XmlPullParser.START_TAG, ns, "_type");
		String type = readText(parser);
		parser.require(XmlPullParser.END_TAG, ns, "_type");

		return type;

	private String readName(XmlPullParser parser) throws IOException,
			XmlPullParserException {
		parser.require(XmlPullParser.START_TAG, ns, "_name");
		String name = readText(parser);
		parser.require(XmlPullParser.END_TAG, ns, "_name");

		return name;

	// extract text values.
	private String readText(XmlPullParser parser) throws IOException,
			XmlPullParserException {
		String result = "";
		if ( == XmlPullParser.TEXT) {
			result = parser.getText();
		return result;

	public class GeoMessage {

		public final String name;
		public final String type;
		public final String action;
		public final String id;
		public final String controlpoints;
		public final String wkid;
		public final String sic;
		public final String uniquedesignation;

		private GeoMessage(String name, String type, String action, String id,
				String controlpoints, String wkid, String sic,
				String uniquedesignation) { = name;
			this.type = type;
			this.action = action; = id;
			this.controlpoints = controlpoints;
			this.wkid = wkid;
			this.sic = sic;
			this.uniquedesignation = uniquedesignation;

Feedback on this topic?