About military messages
Military software used for Situation Awareness and Command & Control pass secure communications between mobile devices in the field and command centers. These special communications consist of either voice or data transmissions. Data communications can contain military messages that define where specific military symbols are located on a map.
You can build an application using the ArcGIS Runtime SDKs for Java or Android to take these military messages and convert them into military symbols to be displayed in a map control on a desktop or laptop device. At this release, the messages can be displayed using symbology from specifications, such as the Department of Defense (DoD) MIL-STD-2525C specification.
Set up your device
Supported symbol dictionaries are provided in the local SDK download resources folder.
You will need to copy the resource contents to your target device. The default location on your device is:/<[EXTERNAL-RESOURCE-DIR]/ArcGIS/SymbolDictionary
Example Default directory structure
+ mnt + sdcard + ArcGIS +SymbolDictionary + MessageTypes - Chemlight.json - PositionReport.json - SpotReport.json - mil2525c.dat
The directory structure above is dependent on your device structure's external sdcard location and which symbol dictionary you have installed in the default location. The MIL-STD-2525C symbol dictionary is dependent on its specific message types.
At this release, you can't have more than one symbol dictionary installed in the default directory location. The MessageProcessor class provides an overloaded constructor, which takes a String representing the directory location for the symbols. Use this constructor for one of the symbol dictionaries to have two resources provisioned to a single device.
You can use the Android Debug Bridge (adb) tool provided by your Android SDK to push the resource to your device. An advanced symbology sample is available and explains how to set up the device in more detail. Refer to these resources to set up your device for application development to support military messages.
A MessageGroupLayer extends a GroupLayer as a collection of layers that can be of any type. It extends from the Layer class and has properties such as visibility, opacity, extent and so on. The most basic functionality that should be provided is the ability to manipulate sublayer visibility, opacity, and order. The layer collection object provides these functions and is essentially a synchronized arraylist and queue of layers. For military purposes, the MessageGroupLayer has a default constructor which creates a new message group layer without a MessageProcessor and can use this instance to create a MessageProcessor. The overloaded constructors provided by the MessageGroupLayer take a SymbolDictionary.DictionaryType parameter to create a MessageProcessor for the given type. It's the MessageProcessor that adds the graphics layers to the MessageGroupLayer. The MessageGroupLayer must be added to an initialized map. If the map is not initialized, an error message shows. Below is an example of creating the MessageProcessor from the constructed MessageGroupLayer:
Creating a message processor
// create a new MessageGroupLayer for MIL 2525C symbol type MessageGroupLayer messageGroupLayer = new MessageGroupLayer(DictionaryType.MIL2525C); // Add layer to the map mMapView.addLayer(messageGroupLayer); // Get the message processor from the GroupLayer MessageProcessor processor = messageGroupLayer.getMessageProcessor();
The message processor handles an incoming message by using message properties to create, delete, update, or otherwise change the state of a graphic (geometry and attributes). The message processor determines which message properties should persist on graphic as attributes. If necessary, the layer (and associated renderer) for the graphic is created and added to the group layer. With 2525C, only one geometry type is stored in a graphics layer, and the layers are z-ordered points->lines->polygons (ordering of layers with the same geometry type is arbitrary).
There are 2 ways to create a message object and process it.
- Setting properties programmatically
- Using the MessageHelper class.
The workflow for createing a Message and processing it programmatically:
Message message = new Message(); UUID uuid = UUID.randomUUID(); message.setID(uuid.toString()); message.setProperty("_Type", "position_report"); message.setProperty("_Action", "update"); message.setProperty("_Control_Points", "7846271.25206,4091857.83028"); message.setProperty("sic", "SFGPUCRRL--E---"); message.setProperty("_WKID", "3857"); message.setProperty("UniqueDesignation", "Mad dog"); processor.processMessage(message);
The MessageHelper class provides user-friendly property names and convenience methods to create messsages:
// create a list of control points for input into message Point point1 = new Point(x1, x2); ArrayList<Point> controlPoints = new ArrayList<Point>(1); controlPoints.add(point1); // create the Map of properties HashMap<String, Object> properties = new HashMap<String, Object>(); properties.put("sic", "SFGPEVC--------"); properties.put("uniquedesignation", "Tex"); Message msg1 = MessageHelper.create2525CUpdateMessage(UUID.randomUUID() .toString(), "position_report", controlPoints, properties); // process message and add point processor.processMessage(msg1);
Messages are logically transient in that they have no (direct) representation in the map or message processor. For update scenarios (for example, military chemlight), the message processorallows the re-creation of a message from a graphic or previous message ID. For 2525C, this is the same as the message previously passed in. The only exception is the action property (for example, update, delete and so on), which is empty. Initially, all properties of the message (except action) persist on the graphic to support this.
Graphic clickedGraphic = null; Message newMsg = msgProcessor.createMessageFrom(clickedGraphic); //if you want to use the message (perform an update), you need to set the action msg.setProperty(":ACTION", "UPDATE"); //process the message msgProcessor.processMessage(newMsg);
Messages can contain the WKID for the spatial reference but if omitted, the default spatial reference is used. This defaults to WGS84.Message
Message contains properties that can be processed by the message processor. All properties are name-value pairs except for the message ID.
Symbol dictionary searching
The group of classes that support functionality to allow for the filtering of symbols contained in a dictionary renderer are SymbolDictionary, SymbolDictionaryQuery, and SymbolDictionaryFilter. Given a filtered list of symbols, other methods can be used to return attributes, keywords, and the graphic for a symbol. The SymbolDictionary class contains functionality to get information about the dictionary including lists of symbols and their associated information. The SymbolDictionaryQuery and SymbolDictionaryFilter classes build queries against the symbol dictionary to return a list of symbols relevant to the application user. To perform a search for symbols that contain given keywords, the code looks as follows:
//The getKeywords() method is called on the SymbolDictionary class //which will return a list of keywords used in that dictionary. SymbolDictionary symbDict = new SymbolDictionary(DictionaryType.MIL2525C); List<string> keywords = symbDict.getKeywords(); //code goes here to take the keywords list and add the names into a picker //One or more of these keywords will be added to the instance of the //SymbolDictionaryQuery class using the addKeyword method. SymbolDictionaryQuery query = new SymbolDictionaryQuery(); query.addKeyword("Appendix X"); query.addKeyword("Friendly"); //The SymbolDictionaryFilter class is used with SymbolDictionaryQuery to // query the symbol dictionary to get a filtered list of symbols SymbolDictionaryFilter symDictFilter = new SymbolDictionaryFilter(); symbDict.addFilter(symDictFilter); String symbolName = symDictFilter.getName();
The symbol graphic can be obtained using the getSymbolImage method. This takes a symbol name that came from a list of symbol names returned in a getSymbolNames call and an Android Bitmap.
//get the symbol graphic from the name and Android Bitmap image // returns true if symbol was successfully generated boolean = symbDict.getSymbolImage("Utility Vehicle U", bitMapImg);