Skip to content
This repository has been archived by the owner on Oct 7, 2024. It is now read-only.

Commit

Permalink
refactored MatrixApiActivity and XML
Browse files Browse the repository at this point in the history
  • Loading branch information
langsmith authored and Langston Smith committed Sep 2, 2019
1 parent c3332c5 commit aea0eba
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 88 deletions.
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
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;
import androidx.cardview.widget.CardView;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.LinearSnapHelper;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.SnapHelper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
Expand All @@ -24,40 +17,52 @@
import com.mapbox.geojson.Point;
import com.mapbox.mapboxandroiddemo.R;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.annotations.Icon;
import com.mapbox.mapboxsdk.annotations.IconFactory;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapView;
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;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.cardview.widget.CardView;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.LinearSnapHelper;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.SnapHelper;
import retrofit2.Call;
import retrofit2.Callback;
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<Point> pointList;
private List<SingleRecyclerViewMatrixLocation> matrixLocationList;
private MapView mapView;
private MapboxMap mapboxMap;
private List<Point> pointList;
private FeatureCollection featureCollection;
private RecyclerView recyclerView;
private MatrixApiLocationRecyclerViewAdapter matrixApiLocationRecyclerViewAdapter;
private ArrayList<SingleRecyclerViewMatrixLocation> matrixLocationList;

@Override
protected void onCreate(Bundle savedInstanceState) {
Expand All @@ -70,41 +75,41 @@ 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);
mapView.getMapAsync(new OnMapReadyCallback() {
@Override
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();

// Set up the recyclerview of charging station cards
initRecyclerView();

mapboxMap.setOnMarkerClickListener(new MapboxMap.OnMarkerClickListener() {
@Override
public boolean onMarkerClick(@NonNull Marker marker) {

// Make a call to the Mapbox Matrix API
makeMapboxMatrixApiCall(getClickedMarkerNumInPositionList(marker), Point.fromLngLat(
marker.getPosition().getLongitude(), marker.getPosition().getLatitude()));
return false;
}
});
mapboxMap.addOnMapClickListener(MatrixApiActivity.this);
Toast.makeText(MatrixApiActivity.this, R.string.click_on_marker_instruction_toast,
Toast.LENGTH_SHORT).show();
}
Expand All @@ -113,23 +118,32 @@ 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<Feature> 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<Feature> 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;
}

/**
* 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());
Expand All @@ -138,8 +152,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()
.accessToken(getString(R.string.access_token))
Expand All @@ -152,18 +170,19 @@ private void makeMapboxMatrixApiCall(final int markerPositionInList, Point point
@Override
public void onResponse(Call<MatrixResponse> call,
Response<MatrixResponse> response) {
List<Double[]> durationsToAllOfTheLocationsFromTheOrigin = response.body().durations();
for (int x = 0; x < durationsToAllOfTheLocationsFromTheOrigin.size(); x++) {
String finalConvertedFormattedDistance = String.valueOf(new DecimalFormat("#.##")
.format(TurfConversion.convertLength(
durationsToAllOfTheLocationsFromTheOrigin.get(markerPositionInList)[x],
"meters", "miles")));
if (x == markerPositionInList) {
matrixLocationList.get(x).setDistanceFromOrigin(finalConvertedFormattedDistance);
}
if (x != markerPositionInList) {
matrixLocationList.get(x).setDistanceFromOrigin(finalConvertedFormattedDistance);
matrixApiLocationRecyclerViewAdapter.notifyDataSetChanged();
if (response.body() != null) {
List<Double[]> durationsToAllOfTheLocationsFromTheOrigin = response.body().durations();
if (durationsToAllOfTheLocationsFromTheOrigin != null) {
for (int x = 0; x < durationsToAllOfTheLocationsFromTheOrigin.size(); x++) {
String finalConvertedFormattedDistance = String.valueOf(new DecimalFormat("#.##").format(
TurfConversion.convertLength(
durationsToAllOfTheLocationsFromTheOrigin.get(markerPositionInList)[x],
"meters", "miles")));
matrixLocationList.get(x).setDistanceFromOrigin(finalConvertedFormattedDistance);
if (x != markerPositionInList) {
matrixApiLocationRecyclerViewAdapter.notifyDataSetChanged();
}
}
}
}
}
Expand All @@ -172,23 +191,11 @@ public void onResponse(Call<MatrixResponse> call,
public void onFailure(Call<MatrixResponse> call, Throwable throwable) {
Toast.makeText(MatrixApiActivity.this, R.string.call_error,
Toast.LENGTH_SHORT).show();
Timber.d( "onResponse onFailure");
Timber.d("onResponse onFailure");
}
});
}

private void addMarkers() {
Icon lightningBoltIcon = IconFactory.getInstance(MatrixApiActivity.this)
.fromResource(R.drawable.lightning_bolt);
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
Expand All @@ -205,8 +212,10 @@ private String loadGeoJsonFromAsset(String filename) {
}
}

private void initPositionListFromGeoJsonFile() {

/**
* 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"));

Expand All @@ -215,20 +224,24 @@ private void initPositionListFromGeoJsonFile() {

// Get the position of each GeoJSON feature and build the list of Position
// objects for eventual use in the Matrix API call
for (Feature singleLocation : featureCollection.features()) {
pointList.add((Point) singleLocation.geometry());
if (featureCollection != null && 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<>();
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()));
matrixLocationList.add(singleRecyclerViewLocation);
if (featureCollection != null && featureCollection.features() != null) {
for (Feature feature : featureCollection.features()) {
SingleRecyclerViewMatrixLocation singleRecyclerViewLocation = new SingleRecyclerViewMatrixLocation();
singleRecyclerViewLocation.setName(feature.getStringProperty(STATION_NAME_PROPERTY));
matrixLocationList.add(singleRecyclerViewLocation);
}
}
}

Expand Down Expand Up @@ -281,7 +294,6 @@ protected void onSaveInstanceState(Bundle outState) {
class SingleRecyclerViewMatrixLocation {

private String name;
private LatLng locationLatLng;
private String distanceFromOrigin;

public String getName() {
Expand All @@ -299,12 +311,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<MatrixApiLocationRecyclerViewAdapter.MyViewHolder> {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
mapbox:mapbox_cameraTargetLat="42.3600825"
mapbox:mapbox_cameraTargetLng="-71.0588801"
mapbox:mapbox_cameraZoom="11.193"
mapbox:mapbox_uiCompassMarginTop="79dp"
/>

<androidx.recyclerview.widget.RecyclerView
Expand Down
2 changes: 1 addition & 1 deletion MapboxAndroidDemo/src/main/res/values/activity_strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@
<!-- Matrix API -->
<string name="call_error">Oh no! The call to the Directions Matrix API failed</string>
<string name="miles_distance">%1$s miles</string>
<string name="click_on_marker_instruction_toast">Click on a bolt marker to get started</string>
<string name="click_on_marker_instruction_toast">Click on a bolt icon to get started</string>

<!-- Geocoding -->
<string name="latitude">latitude</string>
Expand Down

0 comments on commit aea0eba

Please sign in to comment.