From 0441d3a655e41ba699cdfb6879c5c10f531d51e7 Mon Sep 17 00:00:00 2001 From: langsmith Date: Mon, 26 Aug 2019 15:29:32 -0700 Subject: [PATCH 1/2] refactored MatrixApiActivity and XML --- .../javaservices/MatrixApiActivity.java | 156 ++++++++++-------- .../main/res/layout/activity_matrix_api.xml | 1 + .../src/main/res/values/activity_strings.xml | 2 +- 3 files changed, 92 insertions(+), 67 deletions(-) diff --git a/MapboxAndroidDemo/src/main/java/com/mapbox/mapboxandroiddemo/examples/javaservices/MatrixApiActivity.java b/MapboxAndroidDemo/src/main/java/com/mapbox/mapboxandroiddemo/examples/javaservices/MatrixApiActivity.java index 7d8b60a48..5fd710faa 100644 --- a/MapboxAndroidDemo/src/main/java/com/mapbox/mapboxandroiddemo/examples/javaservices/MatrixApiActivity.java +++ b/MapboxAndroidDemo/src/main/java/com/mapbox/mapboxandroiddemo/examples/javaservices/MatrixApiActivity.java @@ -1,6 +1,7 @@ package com.mapbox.mapboxandroiddemo.examples.javaservices; import android.content.Context; +import android.graphics.BitmapFactory; import android.os.Bundle; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; @@ -33,6 +34,8 @@ import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; import com.mapbox.mapboxsdk.maps.Style; +import com.mapbox.mapboxsdk.style.layers.SymbolLayer; +import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; import com.mapbox.turf.TurfConversion; import java.io.InputStream; @@ -46,19 +49,26 @@ import retrofit2.Response; import timber.log.Timber; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAllowOverlap; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconIgnorePlacement; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage; + /** - * Use the Mapbox Java Services SDK's Matrix API to retrieve travel times between many points. + * Use the Mapbox Java SDK's Matrix API to retrieve travel times between many points. */ -public class MatrixApiActivity extends AppCompatActivity { +public class MatrixApiActivity extends AppCompatActivity implements MapboxMap.OnMapClickListener { + private static final String ICON_ID = "ICON_ID"; + private static final String STATION_NAME_PROPERTY = "Station_Name"; + private static final String SOURCE_ID = "SOURCE_ID"; + private static final String LAYER_ID = "LAYER_ID"; + private List pointList; + private List matrixLocationList; private MapView mapView; private MapboxMap mapboxMap; - private List pointList; private FeatureCollection featureCollection; - private RecyclerView recyclerView; private MatrixApiLocationRecyclerViewAdapter matrixApiLocationRecyclerViewAdapter; - private ArrayList matrixLocationList; @Override protected void onCreate(Bundle savedInstanceState) { @@ -71,10 +81,8 @@ protected void onCreate(Bundle savedInstanceState) { // This contains the MapView in XML and needs to be called after the access token is configured. setContentView(R.layout.activity_matrix_api); - recyclerView = findViewById(R.id.matrix_api_recyclerview); - - // Create list of positions from local GeoJSON file - initPositionListFromGeoJsonFile(); + // Create a FeatureCollection via local GeoJSON file + initFeatureCollection(); mapView = findViewById(R.id.mapView); mapView.onCreate(savedInstanceState); @@ -83,12 +91,24 @@ protected void onCreate(Bundle savedInstanceState) { public void onMapReady(@NonNull final MapboxMap mapboxMap) { MatrixApiActivity.this.mapboxMap = mapboxMap; - mapboxMap.setStyle(new Style.Builder().fromUri("mapbox://styles/mapbox/cj8gg22et19ot2rnz65958fkn"), + mapboxMap.setStyle(new Style.Builder().fromUri("mapbox://styles/mapbox/cj8gg22et19ot2rnz65958fkn") + // Add the SymbolLayer icon image to the map style + .withImage(ICON_ID, BitmapFactory.decodeResource( + MatrixApiActivity.this.getResources(), R.drawable.lightning_bolt)) + + // Adding a GeoJson source for the SymbolLayer icons. + .withSource(new GeoJsonSource(SOURCE_ID, featureCollection)) + + // Adding the actual SymbolLayer to the map style. + .withLayer(new SymbolLayer(LAYER_ID, SOURCE_ID) + .withProperties( + iconImage(ICON_ID), + iconAllowOverlap(true), + iconIgnorePlacement(true)) + ), new Style.OnStyleLoaded() { @Override public void onStyleLoaded(@NonNull Style style) { - // Add markers to the map - addMarkers(); // Set up list of locations to pass to the recyclerview initMatrixLocationListForRecyclerView(); @@ -96,16 +116,8 @@ public void onStyleLoaded(@NonNull Style style) { // Set up the recyclerview of charging station cards initRecyclerView(); - mapboxMap.setOnMarkerClickListener(new MapboxMap.OnMarkerClickListener() { - @Override - public boolean onMarkerClick(@NonNull Marker marker) { + mapboxMap.addOnMapClickListener(MatrixApiActivity.this); - // Make a call to the Mapbox Matrix API - makeMapboxMatrixApiCall(getClickedMarkerNumInPositionList(marker), Point.fromLngLat( - marker.getPosition().getLongitude(), marker.getPosition().getLatitude())); - return false; - } - }); Toast.makeText(MatrixApiActivity.this, R.string.click_on_marker_instruction_toast, Toast.LENGTH_SHORT).show(); } @@ -114,23 +126,51 @@ public boolean onMarkerClick(@NonNull Marker marker) { }); } - private int getClickedMarkerNumInPositionList(Marker clickedMarker) { - int clickedMarkerIndexPositionInList = -1; - if (clickedMarker != null) { - for (Marker singleMarker : mapboxMap.getMarkers()) { - if (singleMarker == clickedMarker) { - clickedMarkerIndexPositionInList = mapboxMap.getMarkers().indexOf(singleMarker); + @Override + public boolean onMapClick(@NonNull LatLng point) { + List renderedStationFeatures = mapboxMap.queryRenderedFeatures( + mapboxMap.getProjection().toScreenLocation(point), LAYER_ID); + if (!renderedStationFeatures.isEmpty()) { + Point pointOfSelectedStation = (Point) renderedStationFeatures.get(0).geometry(); + if (pointOfSelectedStation != null) { + String selectedBoltFeatureName = renderedStationFeatures.get(0).getStringProperty(STATION_NAME_PROPERTY); + List featureList = featureCollection.features(); + for (int i = 0; i < featureList.size(); i++) { + if (featureList.get(i).getStringProperty(STATION_NAME_PROPERTY).equals(selectedBoltFeatureName)) { + makeMapboxMatrixApiCall(i); + } } } - return clickedMarkerIndexPositionInList; - } else { - return 0; } + return true; } + /** + * Create a {@link FeatureCollection} from a locally stored asset file. + */ + private void initFeatureCollection() { + // Get GeoJSON features from GeoJSON file in the assets folder + featureCollection = FeatureCollection.fromJson(loadGeoJsonFromAsset("boston_charge_stations.geojson")); + + // Initialize List for eventual use in the Matrix API call + pointList = new ArrayList<>(); + + // Get the position of each GeoJSON feature and build the list of Position + // objects for eventual use in the Matrix API call + if (featureCollection != null && featureCollection.features() != null) { + for (Feature singleLocation : featureCollection.features()) { + pointList.add((Point) singleLocation.geometry()); + } + } + } + + /** + * Set up the RecyclerView, which will display the travel distances to each charge station. + */ private void initRecyclerView() { matrixApiLocationRecyclerViewAdapter = new MatrixApiLocationRecyclerViewAdapter(this, matrixLocationList); + RecyclerView recyclerView = findViewById(R.id.matrix_api_recyclerview); recyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext(), LinearLayoutManager.HORIZONTAL, true)); recyclerView.setItemAnimator(new DefaultItemAnimator()); @@ -139,7 +179,12 @@ private void initRecyclerView() { snapHelper.attachToRecyclerView(recyclerView); } - private void makeMapboxMatrixApiCall(final int markerPositionInList, Point pointOfClickedMarker) { + /** + * Make a call to the Mapbox Matrix API to get the travel distances to each charge station. + * + * @param markerPositionInList the position of the tapped bolt icon {@link Feature} in the FeatureCollection. + */ + private void makeMapboxMatrixApiCall(final int markerPositionInList) { // Build Mapbox Matrix API parameters MapboxMatrix directionsMatrixClient = MapboxMatrix.builder() @@ -157,15 +202,12 @@ public void onResponse(Call call, List durationsToAllOfTheLocationsFromTheOrigin = response.body().durations(); if (durationsToAllOfTheLocationsFromTheOrigin != null) { for (int x = 0; x < durationsToAllOfTheLocationsFromTheOrigin.size(); x++) { - String finalConvertedFormattedDistance = String.valueOf(new DecimalFormat("#.##") - .format(TurfConversion.convertLength( + String finalConvertedFormattedDistance = String.valueOf(new DecimalFormat("#.##").format( + TurfConversion.convertLength( durationsToAllOfTheLocationsFromTheOrigin.get(markerPositionInList)[x], "meters", "miles"))); - if (x == markerPositionInList) { - matrixLocationList.get(x).setDistanceFromOrigin(finalConvertedFormattedDistance); - } + matrixLocationList.get(x).setDistanceFromOrigin(finalConvertedFormattedDistance); if (x != markerPositionInList) { - matrixLocationList.get(x).setDistanceFromOrigin(finalConvertedFormattedDistance); matrixApiLocationRecyclerViewAdapter.notifyDataSetChanged(); } } @@ -177,7 +219,7 @@ public void onResponse(Call call, public void onFailure(Call call, Throwable throwable) { Toast.makeText(MatrixApiActivity.this, R.string.call_error, Toast.LENGTH_SHORT).show(); - Timber.d( "onResponse onFailure"); + Timber.d("onResponse onFailure"); } }); } @@ -204,7 +246,7 @@ private String loadGeoJsonFromAsset(String filename) { byte[] buffer = new byte[size]; is.read(buffer); is.close(); - return new String(buffer, Charset.forName("UTF-8")); + return new String(buffer, Charset.forName("UTF-8")); } catch (Exception exception) { Timber.d(exception.toString(), "Exception Loading GeoJSON: "); exception.printStackTrace(); @@ -212,32 +254,15 @@ private String loadGeoJsonFromAsset(String filename) { } } - private void initPositionListFromGeoJsonFile() { - - // Get GeoJSON features from GeoJSON file in the assets folder - featureCollection = FeatureCollection.fromJson(loadGeoJsonFromAsset("boston_charge_stations.geojson")); - - // Initialize List for eventual use in the Matrix API call - pointList = new ArrayList<>(); - - // Get the position of each GeoJSON feature and build the list of Position - // objects for eventual use in the Matrix API call - if (featureCollection.features() != null) { - for (Feature singleLocation : featureCollection.features()) { - pointList.add((Point) singleLocation.geometry()); - } - } - } - + /** + * Create a list of {@link SingleRecyclerViewMatrixLocation} objects to eventually use in the RecyclerView. + */ private void initMatrixLocationListForRecyclerView() { matrixLocationList = new ArrayList<>(); - if (featureCollection.features() != null) { + if (featureCollection != null && featureCollection.features() != null) { for (Feature feature : featureCollection.features()) { SingleRecyclerViewMatrixLocation singleRecyclerViewLocation = new SingleRecyclerViewMatrixLocation(); - singleRecyclerViewLocation.setName(feature.getStringProperty("Station_Name")); - singleRecyclerViewLocation.setLocationLatLng(new LatLng(((Point) - feature.geometry()).latitude(), - ((Point) feature.geometry()).longitude())); + singleRecyclerViewLocation.setName(feature.getStringProperty(STATION_NAME_PROPERTY)); matrixLocationList.add(singleRecyclerViewLocation); } } @@ -310,12 +335,11 @@ public String getDistanceFromOrigin() { public void setDistanceFromOrigin(String distanceFromOrigin) { this.distanceFromOrigin = distanceFromOrigin; } - - public void setLocationLatLng(LatLng locationLatLng) { - this.locationLatLng = locationLatLng; - } } + /** + * The adapter for this example's RecyclerView. + */ static class MatrixApiLocationRecyclerViewAdapter extends RecyclerView.Adapter { @@ -364,4 +388,4 @@ static class MyViewHolder extends RecyclerView.ViewHolder { } } } -} +} \ No newline at end of file diff --git a/MapboxAndroidDemo/src/main/res/layout/activity_matrix_api.xml b/MapboxAndroidDemo/src/main/res/layout/activity_matrix_api.xml index 40a745834..6968634a4 100644 --- a/MapboxAndroidDemo/src/main/res/layout/activity_matrix_api.xml +++ b/MapboxAndroidDemo/src/main/res/layout/activity_matrix_api.xml @@ -11,6 +11,7 @@ mapbox:mapbox_cameraTargetLat="42.3600825" mapbox:mapbox_cameraTargetLng="-71.0588801" mapbox:mapbox_cameraZoom="11.193" + mapbox:mapbox_uiCompassMarginTop="79dp" /> Oh no! The call to the Directions Matrix API failed %1$s miles - Click on a bolt marker to get started + Click on a bolt icon to get started latitude From b139a7ad0d988ab12d3e345a7e9390a809c03601 Mon Sep 17 00:00:00 2001 From: Langston Smith Date: Mon, 7 Oct 2019 09:19:43 -0700 Subject: [PATCH 2/2] initial changes based on lukasz review --- .../javaservices/MatrixApiActivity.java | 29 +++++-------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/MapboxAndroidDemo/src/main/java/com/mapbox/mapboxandroiddemo/examples/javaservices/MatrixApiActivity.java b/MapboxAndroidDemo/src/main/java/com/mapbox/mapboxandroiddemo/examples/javaservices/MatrixApiActivity.java index 5fd710faa..84b67bd0f 100644 --- a/MapboxAndroidDemo/src/main/java/com/mapbox/mapboxandroiddemo/examples/javaservices/MatrixApiActivity.java +++ b/MapboxAndroidDemo/src/main/java/com/mapbox/mapboxandroiddemo/examples/javaservices/MatrixApiActivity.java @@ -90,7 +90,6 @@ protected void onCreate(Bundle savedInstanceState) { @Override public void onMapReady(@NonNull final MapboxMap mapboxMap) { MatrixApiActivity.this.mapboxMap = mapboxMap; - mapboxMap.setStyle(new Style.Builder().fromUri("mapbox://styles/mapbox/cj8gg22et19ot2rnz65958fkn") // Add the SymbolLayer icon image to the map style .withImage(ICON_ID, BitmapFactory.decodeResource( @@ -131,13 +130,15 @@ public boolean onMapClick(@NonNull LatLng point) { List renderedStationFeatures = mapboxMap.queryRenderedFeatures( mapboxMap.getProjection().toScreenLocation(point), LAYER_ID); if (!renderedStationFeatures.isEmpty()) { - Point pointOfSelectedStation = (Point) renderedStationFeatures.get(0).geometry(); - if (pointOfSelectedStation != null) { - String selectedBoltFeatureName = renderedStationFeatures.get(0).getStringProperty(STATION_NAME_PROPERTY); + Feature featureOfSelectedStation = renderedStationFeatures.get(0); + if (featureOfSelectedStation != null) { + String selectedBoltFeatureName = featureOfSelectedStation.getStringProperty(STATION_NAME_PROPERTY); List featureList = featureCollection.features(); - for (int i = 0; i < featureList.size(); i++) { - if (featureList.get(i).getStringProperty(STATION_NAME_PROPERTY).equals(selectedBoltFeatureName)) { - makeMapboxMatrixApiCall(i); + if (featureList != null) { + for (int i = 0; i < featureList.size(); i++) { + if (featureList.get(i).getStringProperty(STATION_NAME_PROPERTY).equals(selectedBoltFeatureName)) { + makeMapboxMatrixApiCall(i); + } } } } @@ -224,20 +225,6 @@ public void onFailure(Call call, Throwable throwable) { }); } - private void addMarkers() { - Icon lightningBoltIcon = IconFactory.getInstance(MatrixApiActivity.this) - .fromResource(R.drawable.lightning_bolt); - if (featureCollection.features() != null) { - for (Feature feature : featureCollection.features()) { - mapboxMap.addMarker(new MarkerOptions() - .position(new LatLng(feature.getProperty("Latitude").getAsDouble(), - feature.getProperty("Longitude").getAsDouble())) - .snippet(feature.getStringProperty("Station_Name")) - .icon(lightningBoltIcon)); - } - } - } - private String loadGeoJsonFromAsset(String filename) { try { // Load GeoJSON file from local asset folder