Highlight Features Sample

The purpose of this sample is to show how to highlight selected features on a map. This sample allows you to select a layer and identify features in that layer. The identified features are then highlighted on the map and a toast that contains information of the selected features is displayed. A GraphicLayer object is used to highlight the identified features.

Features

  • GraphicsLayer
  • ArcGISTiledMapServiceLayer

Sample Design

This sample has a MapView that has two layers: ArcGISTiledMapServiceLayer and GraphicsLayer. The ArcGISTiledMapServiceLayer points to a map service on one of Esri's servers, while the GraphicsLayer holds graphic elements that highlight features selected as a result of an Identify operation. When the sample application starts, a MapView, ArcGISTiledMapServiceLayer, and GraphicsLayer are instantiated, some listener methods (SingleTap and LongPress) are added to the MapView, and other Android user interface (UI) elements (such as AlertDialog and Buttons) are instantiated as well.

When you select a layer from the Action Bar, then press the screen for 2 to 3 seconds (LongPress), an Identify task is executed using the selected layer and the press location. When IdentifyTask executes, features that are returned from the server as results are highlighted as graphic elements on the GraphicsLayer. A callout is also instantiated and displayed that includes details of the highlighted features. The MapView's onLongPress() handler executes the IdentifyTask, creates a Graphic object with appropriate symbology based on the layer's geometry type, and adds Graphic objects to the GraphicsLayer. This application also retains its state when the device is flipped or when you switch to another application.

Sample Code

/* Copyright 2014 ESRI
 *
 * All rights reserved under the copyright laws of the United States
 * and applicable international laws, treaties, and conventions.
 *
 * You may freely redistribute and use this sample code, with or
 * without modification, provided you include the original copyright
 * notice and use restrictions.
 *
 * See the Sample code usage restrictions document for further information.
 *
 */

package com.esri.arcgis.android.samples.highlightfeatures;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Random;

import android.app.ActionBar;
import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import com.esri.android.map.Callout;
import com.esri.android.map.GraphicsLayer;
import com.esri.android.map.MapView;
import com.esri.android.map.ags.ArcGISTiledMapServiceLayer;
import com.esri.android.map.event.OnLongPressListener;
import com.esri.android.map.event.OnSingleTapListener;
import com.esri.core.geometry.Envelope;
import com.esri.core.geometry.Geometry;
import com.esri.core.geometry.Point;
import com.esri.core.map.Graphic;
import com.esri.core.symbol.SimpleFillSymbol;
import com.esri.core.symbol.SimpleLineSymbol;
import com.esri.core.symbol.SimpleMarkerSymbol;
import com.esri.core.symbol.SimpleMarkerSymbol.STYLE;
import com.esri.core.tasks.identify.IdentifyParameters;
import com.esri.core.tasks.identify.IdentifyResult;
import com.esri.core.tasks.identify.IdentifyTask;

/**
 * The purpose of this sample is to show how to highlight selected features on a
 * map. This sample allows you to select a layer and identify features in that
 * layer. The identified features are then highlighted on the map and a Toast
 * that contains information of the selected features is displayed. A
 * GraphicLayer object is used to highlight the identified features.
 * 
 */
public class HighlightFeatures extends Activity {

	// ArcGIS Android elements
	MapView mapView = null;
	ArcGISTiledMapServiceLayer tiledMapServiceLayer = null;
	GraphicsLayer graphicsLayer;
	Graphic[] highlightGraphics;
	Callout callout = null;

	HashMap<String, List<String>> featureMap = new HashMap<String, List<String>>();

	// Action bar
	ActionBar action = null;
	String[] layerNames;

	final int[] layerIndexes = new int[] { 6, 7, 8, 28, 37 };
	int selectedLayerIndex = -1;
	ProgressDialog dialog = null;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		setContentView(R.layout.main);
		layerNames = getResources().getStringArray(R.array.menuitems);

		// Initialize ArcGIS Android MapView
		mapView = (MapView) findViewById(R.id.map);
		action = getActionBar();

		// Identify on single tap of map
		mapView.setOnSingleTapListener(new OnSingleTapListener() {

			private static final long serialVersionUID = 1L;

			@Override
			public void onSingleTap(final float x, final float y) {

				if (graphicsLayer.getNumberOfGraphics() > 0) {
					callout = mapView.getCallout();

					Point pnt = mapView.toMapPoint(x, y);

					LayoutInflater inflater = getLayoutInflater();
					View calloutView = inflater.inflate(R.xml.callout, null);

					// Access the internal Textview inside the calloutView.
					TextView begins = (TextView) calloutView
							.findViewById(R.id.calloutBeginsAt);

					// Set Up values
					if (selectedLayerIndex == 0 || selectedLayerIndex == 1
							|| selectedLayerIndex == 2) {
						begins.setText("Road Name: "
								+ System.getProperty("line.separator")
								+ featureMap.get("Road Name"));
					}

					else if (selectedLayerIndex == 3) {
						begins.setText("Boundary: "
								+ System.getProperty("line.separator")
								+ featureMap.get("In County"));
					}

					else {
						begins.setText("Name of Facility: "
								+ System.getProperty("line.separator")
								+ featureMap.get("Name of Facility"));
					}
					begins.setEnabled(true);

					// Set the content, show the view
					callout.setContent(calloutView);
					callout.setOffset(0, 0);
					callout.setCoordinates(pnt);
					callout.setStyle(R.xml.calloutstyle);
					callout.setMaxHeight(100000);
					callout.setMaxWidth(100000);
					callout.refresh();
					callout.show();

				}
			}

		});

		// Long Press listener for map view
		mapView.setOnLongPressListener(new OnLongPressListener() {

			private static final long serialVersionUID = 1L;

			/*
			 * Invoked when user does a Long Press on map. This fires an
			 * identify query for features covered by user's finder, on selected
			 * layer.
			 */
			@Override
			public boolean onLongPress(float x, float y) {
				featureMap.clear();
				try {
					if (tiledMapServiceLayer.isInitialized()
							&& selectedLayerIndex >= 0) {

						graphicsLayer.removeAll();

						// Get the point user clicked on
						Point pointClicked = mapView.toMapPoint(x, y);

						// Set parameters for identify task
						IdentifyParameters inputParameters = new IdentifyParameters();
						inputParameters.setGeometry(pointClicked);
						inputParameters
								.setLayers(new int[] { layerIndexes[selectedLayerIndex] });
						Envelope env = new Envelope();
						mapView.getExtent().queryEnvelope(env);
						inputParameters.setSpatialReference(mapView
								.getSpatialReference());
						inputParameters.setMapExtent(env);
						inputParameters.setDPI(96);
						inputParameters.setMapHeight(mapView.getHeight());
						inputParameters.setMapWidth(mapView.getWidth());
						inputParameters.setTolerance(10);

						// Execute identify task
						MyIdentifyTask mIdenitfy = new MyIdentifyTask();
						mIdenitfy.execute(inputParameters);

					} else {
						Toast toast = Toast
								.makeText(
										getApplicationContext(),
										"Please select a layer to identify features from.",
										Toast.LENGTH_SHORT);
						toast.show();
					}
				} catch (Exception ex) {
					ex.printStackTrace();
				}
				return true;
			}
		});

		tiledMapServiceLayer = new ArcGISTiledMapServiceLayer(getResources()
				.getString(R.string.mapURL));
		graphicsLayer = new GraphicsLayer();

		// Add TiledMapServiceLayer and GraphicsLayer to map
		mapView.addLayer(tiledMapServiceLayer);
		mapView.addLayer(graphicsLayer);
	}

	@Override
	protected void onPause() {
		super.onPause();
		mapView.pause();
	}

	@Override
	protected void onResume() {
		super.onResume();
		mapView.unpause();
	}

	/**
	 * Creates the menu items on the action bar
	 */
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.action, menu);
		return super.onCreateOptionsMenu(menu);
	}

	/**
	 * Action for the item Selected from the menu.
	 */
	public boolean onOptionsItemSelected(MenuItem item) {

		switch (item.getItemId()) {

		case R.id.action_remove:
			Toast.makeText(this, getString(R.string.action_remove),
					Toast.LENGTH_LONG).show();
			graphicsLayer.removeAll();
			callout.hide();
			featureMap.clear();
			return true;

		case R.id.ushighways:
			selectedLayerIndex = 0;
			Toast.makeText(this,
					"Selected " + getString(R.string.USHighways) + " layer",
					Toast.LENGTH_LONG).show();
			featureMap.clear();
			return true;

		case R.id.inter:
			selectedLayerIndex = 1;
			Toast.makeText(this,
					"Selected " + getString(R.string.Interstates) + " layer",
					Toast.LENGTH_LONG).show();
			featureMap.clear();
			return true;

		case R.id.majorminor:
			selectedLayerIndex = 2;
			Toast.makeText(
					this,
					"Selected " + getString(R.string.MajorandMinorStreets)
							+ " layer", Toast.LENGTH_LONG).show();
			featureMap.clear();
			return true;

		case R.id.wb:
			selectedLayerIndex = 3;
			Toast.makeText(this,
					"Selected " + getString(R.string.WaterBodies) + " layer",
					Toast.LENGTH_LONG).show();
			featureMap.clear();
			return true;

		case R.id.cemeteries:
			selectedLayerIndex = 4;
			Toast.makeText(this,
					"Selected " + getString(R.string.Cemetaries) + " layer",
					Toast.LENGTH_LONG).show();
			featureMap.clear();
			return true;

		}
		return false;
	}

	/**
	 * This class is responsible to carry out the query operations which runs on
	 * a separate thread and then publish the results to the UI thread.
	 * 
	 */
	private class MyIdentifyTask extends
			AsyncTask<IdentifyParameters, Void, IdentifyResult[]> {

		IdentifyTask mIdentifyTask;

		@Override
		protected void onPreExecute() {
			// create dialog while working off UI thread
			dialog = ProgressDialog.show(HighlightFeatures.this,
					"Highlight Feature", "Fetching your Features...");

			mIdentifyTask = new IdentifyTask(getString(R.string.mapURL));
		}

		@Override
		protected IdentifyResult[] doInBackground(IdentifyParameters... params) {
			IdentifyResult[] mResult = null;
			if (params != null && params.length > 0) {
				IdentifyParameters mParams = params[0];
				try {
					mResult = mIdentifyTask.execute(mParams);
				} catch (Exception e) {
					e.printStackTrace();
				}

			}
			return mResult;
		}

		@Override
		protected void onPostExecute(IdentifyResult[] results) {

			IdentifyResult result_1;

			// dismiss dialog
			if (dialog.isShowing()) {
				dialog.dismiss();
			}

			if (results != null && results.length > 0) {

				highlightGraphics = new Graphic[results.length];

				Toast toast = Toast.makeText(getApplicationContext(),
						results.length + " features identified\n",
						Toast.LENGTH_LONG);
				toast.setGravity(Gravity.BOTTOM, 0, 0);
				toast.show();

				// Highlight all features that match with results
				for (int i = 0; i < results.length; i++) {
					Geometry geom = results[i].getGeometry();
					String typeName = geom.getType().name();

					result_1 = results[i];

					if (selectedLayerIndex == 0) {

						Random r = new Random();
						int color = Color.rgb(r.nextInt(255), r.nextInt(255),
								r.nextInt(255));

						String layer0 = result_1.getAttributes()
								.get("Road Name").toString();

						if (featureMap.containsKey("Road Name")) {
							featureMap.get("Road Name").add(layer0);
						} else {
							List<String> list = new ArrayList<String>();
							list.add(layer0);
							featureMap.put("Road Name", list);
						}

						// Create appropriate symbol, based on geometry type
						if (typeName.equalsIgnoreCase("point")) {
							SimpleMarkerSymbol sms = new SimpleMarkerSymbol(
									color, 20, STYLE.SQUARE);
							highlightGraphics[i] = new Graphic(geom, sms);

						} else if (typeName.equalsIgnoreCase("polyline")) {
							SimpleLineSymbol sls = new SimpleLineSymbol(color,
									5);
							highlightGraphics[i] = new Graphic(geom, sls);

						} else if (typeName.equalsIgnoreCase("polygon")) {
							SimpleFillSymbol sfs = new SimpleFillSymbol(color);
							sfs.setAlpha(75);
							highlightGraphics[i] = new Graphic(geom, sfs);
						}

						// set the Graphic's geometry, add it to GraphicLayer
						// and
						// refresh the Graphic Layer
						graphicsLayer.addGraphic(highlightGraphics[i]);
					}

					else if (selectedLayerIndex == 1) {

						Random r = new Random();
						int color = Color.rgb(r.nextInt(255), r.nextInt(255),
								r.nextInt(255));

						String layer1 = result_1.getAttributes()
								.get("Road Name").toString();

						if (featureMap.containsKey("Road Name")) {
							featureMap.get("Road Name").add(layer1);
						} else {
							List<String> list = new ArrayList<String>();
							list.add(layer1);
							featureMap.put("Road Name", list);
						}

						// Create appropriate symbol, based on geometry type
						if (typeName.equalsIgnoreCase("point")) {
							SimpleMarkerSymbol sms = new SimpleMarkerSymbol(
									color, 20, STYLE.SQUARE);
							highlightGraphics[i] = new Graphic(geom, sms);
						} else if (typeName.equalsIgnoreCase("polyline")) {
							SimpleLineSymbol sls = new SimpleLineSymbol(color,
									5);
							highlightGraphics[i] = new Graphic(geom, sls);
						} else if (typeName.equalsIgnoreCase("polygon")) {
							SimpleFillSymbol sfs = new SimpleFillSymbol(color);
							sfs.setAlpha(75);
							highlightGraphics[i] = new Graphic(geom, sfs);
						}

						// set the Graphic's geometry, add it to GraphicLayer
						// and
						// refresh the Graphic Layer
						graphicsLayer.addGraphic(highlightGraphics[i]);
					}

					else if (selectedLayerIndex == 2) {

						Random r = new Random();
						int color = Color.rgb(r.nextInt(255), r.nextInt(255),
								r.nextInt(255));

						String layer2 = result_1.getAttributes()
								.get("Road Name").toString();

						if (featureMap.containsKey("Road Name")) {
							featureMap.get("Road Name").add(layer2);
						} else {
							List<String> list = new ArrayList<String>();
							list.add(layer2);
							featureMap.put("Road Name", list);
						}

						// Create appropriate symbol, based on geometry type
						if (typeName.equalsIgnoreCase("point")) {
							SimpleMarkerSymbol sms = new SimpleMarkerSymbol(
									color, 20, STYLE.SQUARE);
							highlightGraphics[i] = new Graphic(geom, sms);

						} else if (typeName.equalsIgnoreCase("polyline")) {
							SimpleLineSymbol sls = new SimpleLineSymbol(color,
									5);
							highlightGraphics[i] = new Graphic(geom, sls);
						} else if (typeName.equalsIgnoreCase("polygon")) {
							SimpleFillSymbol sfs = new SimpleFillSymbol(color);
							sfs.setAlpha(75);
							highlightGraphics[i] = new Graphic(geom, sfs);
						}

						// set the Graphic's geometry, add it to GraphicLayer
						// and
						// refresh the Graphic Layer
						graphicsLayer.addGraphic(highlightGraphics[i]);
					}

					else if (selectedLayerIndex == 3) {

						Random r = new Random();
						int color = Color.rgb(r.nextInt(255), r.nextInt(255),
								r.nextInt(255));

						String layer3 = result_1.getAttributes()
								.get("In County").toString();

						if (featureMap.containsKey("In County")) {
							featureMap.get("In County").add(layer3);
						} else {
							List<String> list = new ArrayList<String>();
							list.add(layer3);
							featureMap.put("In County", list);
						}

						// Create appropriate symbol, based on geometry type
						if (typeName.equalsIgnoreCase("point")) {
							SimpleMarkerSymbol sms = new SimpleMarkerSymbol(
									color, 20, STYLE.SQUARE);
							highlightGraphics[i] = new Graphic(geom, sms);

						} else if (typeName.equalsIgnoreCase("polyline")) {
							SimpleLineSymbol sls = new SimpleLineSymbol(color,
									5);
							highlightGraphics[i] = new Graphic(geom, sls);
						} else if (typeName.equalsIgnoreCase("polygon")) {
							SimpleFillSymbol sfs = new SimpleFillSymbol(color);
							sfs.setAlpha(75);
							highlightGraphics[i] = new Graphic(geom, sfs);
						}

						// set the Graphic's geometry, add it to GraphicLayer
						// and
						// refresh the Graphic Layer
						graphicsLayer.addGraphic(highlightGraphics[i]);

					}

					else {

						Random r = new Random();
						int color = Color.rgb(r.nextInt(255), r.nextInt(255),
								r.nextInt(255));

						String layer4 = result_1.getAttributes()
								.get("Name of Facility").toString();

						if (featureMap.containsKey("Name of Facility")) {
							featureMap.get("Name of Facility").add(layer4);
						} else {
							List<String> list = new ArrayList<String>();
							list.add(layer4);
							featureMap.put("Name of Facility", list);
						}

						// Create appropriate symbol, based on geometry type
						if (typeName.equalsIgnoreCase("point")) {
							SimpleMarkerSymbol sms = new SimpleMarkerSymbol(
									color, 20, STYLE.SQUARE);
							highlightGraphics[i] = new Graphic(geom, sms);
						} else if (typeName.equalsIgnoreCase("polyline")) {
							SimpleLineSymbol sls = new SimpleLineSymbol(color,
									5);
							highlightGraphics[i] = new Graphic(geom, sls);
						} else if (typeName.equalsIgnoreCase("polygon")) {
							SimpleFillSymbol sfs = new SimpleFillSymbol(color);
							sfs.setAlpha(75);
							highlightGraphics[i] = new Graphic(geom, sfs);
						}

						// set the Graphic's geometry, add it to GraphicLayer
						// and
						// refresh the Graphic Layer
						graphicsLayer.addGraphic(highlightGraphics[i]);
					}
				}
			} else {
				Toast toast = Toast.makeText(getApplicationContext(),
						"No features identified.", Toast.LENGTH_SHORT);
				toast.show();
			}
		}
	}
}
Feedback on this topic?