11package com .mapbox .mapboxandroiddemo .examples .javaservices ;
22
33import android .content .Context ;
4+ import android .graphics .BitmapFactory ;
45import android .os .Bundle ;
56import androidx .annotation .NonNull ;
67import androidx .appcompat .app .AppCompatActivity ;
3334import com .mapbox .mapboxsdk .maps .MapboxMap ;
3435import com .mapbox .mapboxsdk .maps .OnMapReadyCallback ;
3536import com .mapbox .mapboxsdk .maps .Style ;
37+ import com .mapbox .mapboxsdk .style .layers .SymbolLayer ;
38+ import com .mapbox .mapboxsdk .style .sources .GeoJsonSource ;
3639import com .mapbox .turf .TurfConversion ;
3740
3841import java .io .InputStream ;
4649import retrofit2 .Response ;
4750import timber .log .Timber ;
4851
52+ import static com .mapbox .mapboxsdk .style .layers .PropertyFactory .iconAllowOverlap ;
53+ import static com .mapbox .mapboxsdk .style .layers .PropertyFactory .iconIgnorePlacement ;
54+ import static com .mapbox .mapboxsdk .style .layers .PropertyFactory .iconImage ;
55+
4956
5057/**
51- * Use the Mapbox Java Services SDK's Matrix API to retrieve travel times between many points.
58+ * Use the Mapbox Java SDK's Matrix API to retrieve travel times between many points.
5259 */
53- public class MatrixApiActivity extends AppCompatActivity {
60+ public class MatrixApiActivity extends AppCompatActivity implements MapboxMap . OnMapClickListener {
5461
62+ private static final String ICON_ID = "ICON_ID" ;
63+ private static final String STATION_NAME_PROPERTY = "Station_Name" ;
64+ private static final String SOURCE_ID = "SOURCE_ID" ;
65+ private static final String LAYER_ID = "LAYER_ID" ;
66+ private List <Point > pointList ;
67+ private List <SingleRecyclerViewMatrixLocation > matrixLocationList ;
5568 private MapView mapView ;
5669 private MapboxMap mapboxMap ;
57- private List <Point > pointList ;
5870 private FeatureCollection featureCollection ;
59- private RecyclerView recyclerView ;
6071 private MatrixApiLocationRecyclerViewAdapter matrixApiLocationRecyclerViewAdapter ;
61- private ArrayList <SingleRecyclerViewMatrixLocation > matrixLocationList ;
6272
6373 @ Override
6474 protected void onCreate (Bundle savedInstanceState ) {
@@ -71,10 +81,8 @@ protected void onCreate(Bundle savedInstanceState) {
7181 // This contains the MapView in XML and needs to be called after the access token is configured.
7282 setContentView (R .layout .activity_matrix_api );
7383
74- recyclerView = findViewById (R .id .matrix_api_recyclerview );
75-
76- // Create list of positions from local GeoJSON file
77- initPositionListFromGeoJsonFile ();
84+ // Create a FeatureCollection via local GeoJSON file
85+ initFeatureCollection ();
7886
7987 mapView = findViewById (R .id .mapView );
8088 mapView .onCreate (savedInstanceState );
@@ -83,29 +91,33 @@ protected void onCreate(Bundle savedInstanceState) {
8391 public void onMapReady (@ NonNull final MapboxMap mapboxMap ) {
8492 MatrixApiActivity .this .mapboxMap = mapboxMap ;
8593
86- mapboxMap .setStyle (new Style .Builder ().fromUri ("mapbox://styles/mapbox/cj8gg22et19ot2rnz65958fkn" ),
94+ mapboxMap .setStyle (new Style .Builder ().fromUri ("mapbox://styles/mapbox/cj8gg22et19ot2rnz65958fkn" )
95+ // Add the SymbolLayer icon image to the map style
96+ .withImage (ICON_ID , BitmapFactory .decodeResource (
97+ MatrixApiActivity .this .getResources (), R .drawable .lightning_bolt ))
98+
99+ // Adding a GeoJson source for the SymbolLayer icons.
100+ .withSource (new GeoJsonSource (SOURCE_ID , featureCollection ))
101+
102+ // Adding the actual SymbolLayer to the map style.
103+ .withLayer (new SymbolLayer (LAYER_ID , SOURCE_ID )
104+ .withProperties (
105+ iconImage (ICON_ID ),
106+ iconAllowOverlap (true ),
107+ iconIgnorePlacement (true ))
108+ ),
87109 new Style .OnStyleLoaded () {
88110 @ Override
89111 public void onStyleLoaded (@ NonNull Style style ) {
90- // Add markers to the map
91- addMarkers ();
92112
93113 // Set up list of locations to pass to the recyclerview
94114 initMatrixLocationListForRecyclerView ();
95115
96116 // Set up the recyclerview of charging station cards
97117 initRecyclerView ();
98118
99- mapboxMap .setOnMarkerClickListener (new MapboxMap .OnMarkerClickListener () {
100- @ Override
101- public boolean onMarkerClick (@ NonNull Marker marker ) {
119+ mapboxMap .addOnMapClickListener (MatrixApiActivity .this );
102120
103- // Make a call to the Mapbox Matrix API
104- makeMapboxMatrixApiCall (getClickedMarkerNumInPositionList (marker ), Point .fromLngLat (
105- marker .getPosition ().getLongitude (), marker .getPosition ().getLatitude ()));
106- return false ;
107- }
108- });
109121 Toast .makeText (MatrixApiActivity .this , R .string .click_on_marker_instruction_toast ,
110122 Toast .LENGTH_SHORT ).show ();
111123 }
@@ -114,23 +126,51 @@ public boolean onMarkerClick(@NonNull Marker marker) {
114126 });
115127 }
116128
117- private int getClickedMarkerNumInPositionList (Marker clickedMarker ) {
118- int clickedMarkerIndexPositionInList = -1 ;
119- if (clickedMarker != null ) {
120- for (Marker singleMarker : mapboxMap .getMarkers ()) {
121- if (singleMarker == clickedMarker ) {
122- clickedMarkerIndexPositionInList = mapboxMap .getMarkers ().indexOf (singleMarker );
129+ @ Override
130+ public boolean onMapClick (@ NonNull LatLng point ) {
131+ List <Feature > renderedStationFeatures = mapboxMap .queryRenderedFeatures (
132+ mapboxMap .getProjection ().toScreenLocation (point ), LAYER_ID );
133+ if (!renderedStationFeatures .isEmpty ()) {
134+ Point pointOfSelectedStation = (Point ) renderedStationFeatures .get (0 ).geometry ();
135+ if (pointOfSelectedStation != null ) {
136+ String selectedBoltFeatureName = renderedStationFeatures .get (0 ).getStringProperty (STATION_NAME_PROPERTY );
137+ List <Feature > featureList = featureCollection .features ();
138+ for (int i = 0 ; i < featureList .size (); i ++) {
139+ if (featureList .get (i ).getStringProperty (STATION_NAME_PROPERTY ).equals (selectedBoltFeatureName )) {
140+ makeMapboxMatrixApiCall (i );
141+ }
123142 }
124143 }
125- return clickedMarkerIndexPositionInList ;
126- } else {
127- return 0 ;
128144 }
145+ return true ;
129146 }
130147
148+ /**
149+ * Create a {@link FeatureCollection} from a locally stored asset file.
150+ */
151+ private void initFeatureCollection () {
152+ // Get GeoJSON features from GeoJSON file in the assets folder
153+ featureCollection = FeatureCollection .fromJson (loadGeoJsonFromAsset ("boston_charge_stations.geojson" ));
154+
155+ // Initialize List<Position> for eventual use in the Matrix API call
156+ pointList = new ArrayList <>();
157+
158+ // Get the position of each GeoJSON feature and build the list of Position
159+ // objects for eventual use in the Matrix API call
160+ if (featureCollection != null && featureCollection .features () != null ) {
161+ for (Feature singleLocation : featureCollection .features ()) {
162+ pointList .add ((Point ) singleLocation .geometry ());
163+ }
164+ }
165+ }
166+
167+ /**
168+ * Set up the RecyclerView, which will display the travel distances to each charge station.
169+ */
131170 private void initRecyclerView () {
132171 matrixApiLocationRecyclerViewAdapter = new MatrixApiLocationRecyclerViewAdapter (this ,
133172 matrixLocationList );
173+ RecyclerView recyclerView = findViewById (R .id .matrix_api_recyclerview );
134174 recyclerView .setLayoutManager (new LinearLayoutManager (getApplicationContext (),
135175 LinearLayoutManager .HORIZONTAL , true ));
136176 recyclerView .setItemAnimator (new DefaultItemAnimator ());
@@ -139,7 +179,12 @@ private void initRecyclerView() {
139179 snapHelper .attachToRecyclerView (recyclerView );
140180 }
141181
142- private void makeMapboxMatrixApiCall (final int markerPositionInList , Point pointOfClickedMarker ) {
182+ /**
183+ * Make a call to the Mapbox Matrix API to get the travel distances to each charge station.
184+ *
185+ * @param markerPositionInList the position of the tapped bolt icon {@link Feature} in the FeatureCollection.
186+ */
187+ private void makeMapboxMatrixApiCall (final int markerPositionInList ) {
143188
144189 // Build Mapbox Matrix API parameters
145190 MapboxMatrix directionsMatrixClient = MapboxMatrix .builder ()
@@ -157,15 +202,12 @@ public void onResponse(Call<MatrixResponse> call,
157202 List <Double []> durationsToAllOfTheLocationsFromTheOrigin = response .body ().durations ();
158203 if (durationsToAllOfTheLocationsFromTheOrigin != null ) {
159204 for (int x = 0 ; x < durationsToAllOfTheLocationsFromTheOrigin .size (); x ++) {
160- String finalConvertedFormattedDistance = String .valueOf (new DecimalFormat ("#.##" )
161- . format ( TurfConversion .convertLength (
205+ String finalConvertedFormattedDistance = String .valueOf (new DecimalFormat ("#.##" ). format (
206+ TurfConversion .convertLength (
162207 durationsToAllOfTheLocationsFromTheOrigin .get (markerPositionInList )[x ],
163208 "meters" , "miles" )));
164- if (x == markerPositionInList ) {
165- matrixLocationList .get (x ).setDistanceFromOrigin (finalConvertedFormattedDistance );
166- }
209+ matrixLocationList .get (x ).setDistanceFromOrigin (finalConvertedFormattedDistance );
167210 if (x != markerPositionInList ) {
168- matrixLocationList .get (x ).setDistanceFromOrigin (finalConvertedFormattedDistance );
169211 matrixApiLocationRecyclerViewAdapter .notifyDataSetChanged ();
170212 }
171213 }
@@ -177,7 +219,7 @@ public void onResponse(Call<MatrixResponse> call,
177219 public void onFailure (Call <MatrixResponse > call , Throwable throwable ) {
178220 Toast .makeText (MatrixApiActivity .this , R .string .call_error ,
179221 Toast .LENGTH_SHORT ).show ();
180- Timber .d ( "onResponse onFailure" );
222+ Timber .d ("onResponse onFailure" );
181223 }
182224 });
183225 }
@@ -204,40 +246,23 @@ private String loadGeoJsonFromAsset(String filename) {
204246 byte [] buffer = new byte [size ];
205247 is .read (buffer );
206248 is .close ();
207- return new String (buffer , Charset .forName ("UTF-8" ));
249+ return new String (buffer , Charset .forName ("UTF-8" ));
208250 } catch (Exception exception ) {
209251 Timber .d (exception .toString (), "Exception Loading GeoJSON: " );
210252 exception .printStackTrace ();
211253 return null ;
212254 }
213255 }
214256
215- private void initPositionListFromGeoJsonFile () {
216-
217- // Get GeoJSON features from GeoJSON file in the assets folder
218- featureCollection = FeatureCollection .fromJson (loadGeoJsonFromAsset ("boston_charge_stations.geojson" ));
219-
220- // Initialize List<Position> for eventual use in the Matrix API call
221- pointList = new ArrayList <>();
222-
223- // Get the position of each GeoJSON feature and build the list of Position
224- // objects for eventual use in the Matrix API call
225- if (featureCollection .features () != null ) {
226- for (Feature singleLocation : featureCollection .features ()) {
227- pointList .add ((Point ) singleLocation .geometry ());
228- }
229- }
230- }
231-
257+ /**
258+ * Create a list of {@link SingleRecyclerViewMatrixLocation} objects to eventually use in the RecyclerView.
259+ */
232260 private void initMatrixLocationListForRecyclerView () {
233261 matrixLocationList = new ArrayList <>();
234- if (featureCollection .features () != null ) {
262+ if (featureCollection != null && featureCollection .features () != null ) {
235263 for (Feature feature : featureCollection .features ()) {
236264 SingleRecyclerViewMatrixLocation singleRecyclerViewLocation = new SingleRecyclerViewMatrixLocation ();
237- singleRecyclerViewLocation .setName (feature .getStringProperty ("Station_Name" ));
238- singleRecyclerViewLocation .setLocationLatLng (new LatLng (((Point )
239- feature .geometry ()).latitude (),
240- ((Point ) feature .geometry ()).longitude ()));
265+ singleRecyclerViewLocation .setName (feature .getStringProperty (STATION_NAME_PROPERTY ));
241266 matrixLocationList .add (singleRecyclerViewLocation );
242267 }
243268 }
@@ -310,12 +335,11 @@ public String getDistanceFromOrigin() {
310335 public void setDistanceFromOrigin (String distanceFromOrigin ) {
311336 this .distanceFromOrigin = distanceFromOrigin ;
312337 }
313-
314- public void setLocationLatLng (LatLng locationLatLng ) {
315- this .locationLatLng = locationLatLng ;
316- }
317338 }
318339
340+ /**
341+ * The adapter for this example's RecyclerView.
342+ */
319343 static class MatrixApiLocationRecyclerViewAdapter extends
320344 RecyclerView .Adapter <MatrixApiLocationRecyclerViewAdapter .MyViewHolder > {
321345
@@ -364,4 +388,4 @@ static class MyViewHolder extends RecyclerView.ViewHolder {
364388 }
365389 }
366390 }
367- }
391+ }
0 commit comments