Java tutorial
/* Copyright 2017 Esri * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.esri.arcgisruntime.sample.findaddress; import java.util.List; import java.util.concurrent.ExecutionException; import android.database.MatrixCursor; import android.graphics.Color; import android.graphics.drawable.BitmapDrawable; import android.os.Bundle; import android.provider.BaseColumns; import android.support.v4.content.ContextCompat; import android.support.v4.widget.SimpleCursorAdapter; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.SearchView; import android.util.Log; import android.view.MotionEvent; import android.widget.TextView; import android.widget.Toast; import com.esri.arcgisruntime.concurrent.ListenableFuture; import com.esri.arcgisruntime.geometry.Point; import com.esri.arcgisruntime.loadable.LoadStatus; import com.esri.arcgisruntime.mapping.ArcGISMap; import com.esri.arcgisruntime.mapping.Basemap; import com.esri.arcgisruntime.mapping.Viewpoint; import com.esri.arcgisruntime.mapping.view.Callout; import com.esri.arcgisruntime.mapping.view.DefaultMapViewOnTouchListener; import com.esri.arcgisruntime.mapping.view.Graphic; import com.esri.arcgisruntime.mapping.view.GraphicsOverlay; import com.esri.arcgisruntime.mapping.view.IdentifyGraphicsOverlayResult; import com.esri.arcgisruntime.mapping.view.MapView; import com.esri.arcgisruntime.symbology.PictureMarkerSymbol; import com.esri.arcgisruntime.tasks.geocode.GeocodeParameters; import com.esri.arcgisruntime.tasks.geocode.GeocodeResult; import com.esri.arcgisruntime.tasks.geocode.LocatorTask; import com.esri.arcgisruntime.tasks.geocode.SuggestResult; public class MainActivity extends AppCompatActivity { private final String TAG = MainActivity.class.getSimpleName(); private final String COLUMN_NAME_ADDRESS = "address"; private final String[] mColumnNames = { BaseColumns._ID, COLUMN_NAME_ADDRESS }; private SearchView mAddressSearchView; private MapView mMapView; private LocatorTask mLocatorTask; private GraphicsOverlay mGraphicsOverlay; private GeocodeParameters mAddressGeocodeParameters; private PictureMarkerSymbol mPinSourceSymbol; private Callout mCallout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // inflate address search view mAddressSearchView = (SearchView) findViewById(R.id.addressSearchView); mAddressSearchView.setIconified(false); mAddressSearchView.setFocusable(false); mAddressSearchView.setQueryHint(getResources().getString(R.string.address_search_hint)); // define pin drawable BitmapDrawable pinDrawable = (BitmapDrawable) ContextCompat.getDrawable(this, R.drawable.pin); try { mPinSourceSymbol = PictureMarkerSymbol.createAsync(pinDrawable).get(); } catch (InterruptedException | ExecutionException e) { Log.e(TAG, "Picture Marker Symbol error: " + e.getMessage()); Toast.makeText(getApplicationContext(), "Failed to load pin drawable.", Toast.LENGTH_LONG).show(); } // set pin to half of native size mPinSourceSymbol.setWidth(19f); mPinSourceSymbol.setHeight(72f); // create a LocatorTask from an online service mLocatorTask = new LocatorTask("http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer"); // inflate MapView from layout mMapView = (MapView) findViewById(R.id.mapView); // create a map with the BasemapType topographic final ArcGISMap map = new ArcGISMap(Basemap.createStreetsVector()); // set the map to be displayed in this view mMapView.setMap(map); // set the map viewpoint to start over North America mMapView.setViewpoint(new Viewpoint(40, -100, 100000000)); // add listener to handle screen taps mMapView.setOnTouchListener(new DefaultMapViewOnTouchListener(this, mMapView) { @Override public boolean onSingleTapConfirmed(MotionEvent motionEvent) { identifyGraphic(motionEvent); return true; } }); // define the graphics overlay mGraphicsOverlay = new GraphicsOverlay(); setupAddressSearchView(); } /** * Sets up the address SearchView. Uses MatrixCursor to show suggestions to the user as the user inputs text. */ private void setupAddressSearchView() { mAddressGeocodeParameters = new GeocodeParameters(); // get place name and address attributes mAddressGeocodeParameters.getResultAttributeNames().add("PlaceName"); mAddressGeocodeParameters.getResultAttributeNames().add("StAddr"); // return only the closest result mAddressGeocodeParameters.setMaxResults(1); mAddressSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String address) { // geocode typed address geoCodeTypedAddress(address); // clear focus from search views mAddressSearchView.clearFocus(); return true; } @Override public boolean onQueryTextChange(String newText) { // as long as newText isn't empty, get suggestions from the locatorTask if (!newText.equals("")) { final ListenableFuture<List<SuggestResult>> suggestionsFuture = mLocatorTask .suggestAsync(newText); suggestionsFuture.addDoneListener(new Runnable() { @Override public void run() { try { // get the results of the async operation List<SuggestResult> suggestResults = suggestionsFuture.get(); MatrixCursor suggestionsCursor = new MatrixCursor(mColumnNames); int key = 0; // add each address suggestion to a new row for (SuggestResult result : suggestResults) { suggestionsCursor.addRow(new Object[] { key++, result.getLabel() }); } // define SimpleCursorAdapter String[] cols = new String[] { COLUMN_NAME_ADDRESS }; int[] to = new int[] { R.id.suggestion_address }; final SimpleCursorAdapter suggestionAdapter = new SimpleCursorAdapter( MainActivity.this, R.layout.suggestion, suggestionsCursor, cols, to, 0); mAddressSearchView.setSuggestionsAdapter(suggestionAdapter); // handle an address suggestion being chosen mAddressSearchView.setOnSuggestionListener(new SearchView.OnSuggestionListener() { @Override public boolean onSuggestionSelect(int position) { return false; } @Override public boolean onSuggestionClick(int position) { // get the selected row MatrixCursor selectedRow = (MatrixCursor) suggestionAdapter .getItem(position); // get the row's index int selectedCursorIndex = selectedRow.getColumnIndex(COLUMN_NAME_ADDRESS); // get the string from the row at index String address = selectedRow.getString(selectedCursorIndex); // use clicked suggestion as query mAddressSearchView.setQuery(address, true); return true; } }); } catch (Exception e) { Log.e(TAG, "Geocode suggestion error: " + e.getMessage()); } } }); } return true; } }); } /** * Identifies the Graphic at the tapped point. * * @param motionEvent containing a tapped screen point */ private void identifyGraphic(MotionEvent motionEvent) { // get the screen point android.graphics.Point screenPoint = new android.graphics.Point(Math.round(motionEvent.getX()), Math.round(motionEvent.getY())); // from the graphics overlay, get graphics near the tapped location final ListenableFuture<IdentifyGraphicsOverlayResult> identifyResultsFuture = mMapView .identifyGraphicsOverlayAsync(mGraphicsOverlay, screenPoint, 10, false); identifyResultsFuture.addDoneListener(new Runnable() { @Override public void run() { try { IdentifyGraphicsOverlayResult identifyGraphicsOverlayResult = identifyResultsFuture.get(); List<Graphic> graphics = identifyGraphicsOverlayResult.getGraphics(); // if a graphic has been identified if (graphics.size() > 0) { //get the first graphic identified Graphic identifiedGraphic = graphics.get(0); showCallout(identifiedGraphic); } else { // if no graphic identified mCallout.dismiss(); } } catch (Exception e) { Log.e(TAG, "Identify error: " + e.getMessage()); } } }); } /** * Shows the Graphic's attributes as a Callout. * * @param graphic containing attributes */ private void showCallout(final Graphic graphic) { // create a TextView for the Callout TextView calloutContent = new TextView(getApplicationContext()); calloutContent.setTextColor(Color.BLACK); // set the text of the Callout to graphic's attributes calloutContent.setText(graphic.getAttributes().get("PlaceName").toString() + "\n" + graphic.getAttributes().get("StAddr").toString()); // get Callout mCallout = mMapView.getCallout(); // set Callout options: animateCallout: true, recenterMap: false, animateRecenter: false mCallout.setShowOptions(new Callout.ShowOptions(true, false, false)); mCallout.setContent(calloutContent); // set the leader position and show the callout // set the leader position and show the callout Point calloutLocation = graphic.computeCalloutLocation(graphic.getGeometry().getExtent().getCenter(), mMapView); mCallout.setGeoElement(graphic, calloutLocation); mCallout.show(); } /** * Geocode an address passed in by the user. * * @param address read in from searchViews */ private void geoCodeTypedAddress(final String address) { // check that address isn't null if (address != null) { // Execute async task to find the address mLocatorTask.addDoneLoadingListener(new Runnable() { @Override public void run() { if (mLocatorTask.getLoadStatus() == LoadStatus.LOADED) { // Call geocodeAsync passing in an address final ListenableFuture<List<GeocodeResult>> geocodeResultListenableFuture = mLocatorTask .geocodeAsync(address, mAddressGeocodeParameters); geocodeResultListenableFuture.addDoneListener(new Runnable() { @Override public void run() { try { // Get the results of the async operation List<GeocodeResult> geocodeResults = geocodeResultListenableFuture.get(); if (geocodeResults.size() > 0) { displaySearchResult(geocodeResults.get(0)); } else { Toast.makeText(getApplicationContext(), getString(R.string.location_not_found) + address, Toast.LENGTH_LONG) .show(); } } catch (InterruptedException | ExecutionException e) { Log.e(TAG, "Geocode error: " + e.getMessage()); Toast.makeText(getApplicationContext(), getString(R.string.geo_locate_error), Toast.LENGTH_LONG).show(); } } }); } else { Log.i(TAG, "Trying to reload locator task"); mLocatorTask.retryLoadAsync(); } } }); mLocatorTask.loadAsync(); } } /** * Turns a GeocodeResult into a Point and adds it to a GraphicOverlay which is then drawn on the map. * * @param geocodeResult a single geocode result */ private void displaySearchResult(GeocodeResult geocodeResult) { // dismiss any callout if (mMapView.getCallout() != null && mMapView.getCallout().isShowing()) { mMapView.getCallout().dismiss(); } // clear map of existing graphics mMapView.getGraphicsOverlays().clear(); mGraphicsOverlay.getGraphics().clear(); // create graphic object for resulting location Point resultPoint = geocodeResult.getDisplayLocation(); Graphic resultLocGraphic = new Graphic(resultPoint, geocodeResult.getAttributes(), mPinSourceSymbol); // add graphic to location layer mGraphicsOverlay.getGraphics().add(resultLocGraphic); // zoom map to result over 3 seconds mMapView.setViewpointAsync(new Viewpoint(geocodeResult.getExtent()), 3); // set the graphics overlay to the map mMapView.getGraphicsOverlays().add(mGraphicsOverlay); showCallout(resultLocGraphic); } @Override protected void onPause() { super.onPause(); mMapView.pause(); } @Override protected void onResume() { super.onResume(); mMapView.resume(); } @Override protected void onDestroy() { super.onDestroy(); mMapView.dispose(); } }