diff --git a/MapboxAndroidDemo/src/global/java/com/mapbox/mapboxandroiddemo/MainActivity.java b/MapboxAndroidDemo/src/global/java/com/mapbox/mapboxandroiddemo/MainActivity.java
index 9b9d4c4be..7f7d31729 100644
--- a/MapboxAndroidDemo/src/global/java/com/mapbox/mapboxandroiddemo/MainActivity.java
+++ b/MapboxAndroidDemo/src/global/java/com/mapbox/mapboxandroiddemo/MainActivity.java
@@ -95,6 +95,7 @@
import com.mapbox.mapboxandroiddemo.examples.labs.PulsingLayerOpacityColorActivity;
import com.mapbox.mapboxandroiddemo.examples.labs.RecyclerViewDirectionsActivity;
import com.mapbox.mapboxandroiddemo.examples.labs.RecyclerViewOnMapActivity;
+import com.mapbox.mapboxandroiddemo.examples.labs.SharedPreferencesActivity;
import com.mapbox.mapboxandroiddemo.examples.labs.SnakingDirectionsRouteActivity;
import com.mapbox.mapboxandroiddemo.examples.labs.SpaceStationLocationActivity;
import com.mapbox.mapboxandroiddemo.examples.labs.SpinningSymbolLayerIconActivity;
@@ -1278,6 +1279,14 @@ private void initializeModels() {
null,
R.string.activity_lab_change_attribution_color_url, true, BuildConfig.MIN_SDK_VERSION));
+ exampleItemModels.add(new ExampleItemModel(
+ R.id.nav_lab,
+ R.string.activity_lab_shared_preferences_title,
+ R.string.activity_lab_shared_preferences_description,
+ new Intent(MainActivity.this, SharedPreferencesActivity.class),
+ null,
+ R.string.activity_lab_shared_preferences_url, true, BuildConfig.MIN_SDK_VERSION));
+
exampleItemModels.add(new ExampleItemModel(
R.id.nav_dds,
R.string.activity_dds_geojson_line_title,
diff --git a/MapboxAndroidDemo/src/main/AndroidManifest.xml b/MapboxAndroidDemo/src/main/AndroidManifest.xml
index c2478d59f..6997bb0f4 100644
--- a/MapboxAndroidDemo/src/main/AndroidManifest.xml
+++ b/MapboxAndroidDemo/src/main/AndroidManifest.xml
@@ -285,6 +285,13 @@
android:name="android.support.PARENT_ACTIVITY"
android:value="com.mapbox.mapboxandroiddemo.MainActivity" />
+
+
+
diff --git a/MapboxAndroidDemo/src/main/java/com/mapbox/mapboxandroiddemo/examples/javaservices/TilequeryActivity.java b/MapboxAndroidDemo/src/main/java/com/mapbox/mapboxandroiddemo/examples/javaservices/TilequeryActivity.java
index ab563b457..e596c58f9 100644
--- a/MapboxAndroidDemo/src/main/java/com/mapbox/mapboxandroiddemo/examples/javaservices/TilequeryActivity.java
+++ b/MapboxAndroidDemo/src/main/java/com/mapbox/mapboxandroiddemo/examples/javaservices/TilequeryActivity.java
@@ -288,6 +288,9 @@ public void onLowMemory() {
@Override
protected void onDestroy() {
super.onDestroy();
+ if (mapboxMap != null) {
+ mapboxMap.removeOnMapClickListener(this);
+ }
mapView.onDestroy();
}
diff --git a/MapboxAndroidDemo/src/main/java/com/mapbox/mapboxandroiddemo/examples/labs/SharedPreferencesActivity.java b/MapboxAndroidDemo/src/main/java/com/mapbox/mapboxandroiddemo/examples/labs/SharedPreferencesActivity.java
new file mode 100644
index 000000000..7afe000b4
--- /dev/null
+++ b/MapboxAndroidDemo/src/main/java/com/mapbox/mapboxandroiddemo/examples/labs/SharedPreferencesActivity.java
@@ -0,0 +1,247 @@
+package com.mapbox.mapboxandroiddemo.examples.labs;
+
+import android.content.SharedPreferences;
+import android.graphics.BitmapFactory;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.mapbox.geojson.Point;
+import com.mapbox.mapboxandroiddemo.R;
+import com.mapbox.mapboxsdk.Mapbox;
+import com.mapbox.mapboxsdk.camera.CameraPosition;
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
+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.PropertyFactory;
+import com.mapbox.mapboxsdk.style.layers.SymbolLayer;
+import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
+
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAllowOverlap;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconOffset;
+
+
+/**
+ * Use shared preferences to save and retrieve data, so that the data can be displayed after closing the app.
+ */
+public class SharedPreferencesActivity extends AppCompatActivity implements OnMapReadyCallback,
+ MapboxMap.OnMapClickListener {
+
+ private static final String SAVED_LAT_KEY = "SAVED_LAT_KEY";
+ private static final String SAVED_LONG_KEY = "SAVED_LONG_KEY";
+ private static final String CLICK_LOCATION_SOURCE_ID = "CLICK_LOCATION_SOURCE_ID";
+ private static final String CLICK_LOCATION_ICON_ID = "CLICK_LOCATION_ICON_ID";
+ private static final String CLICK_LOCATION_LAYER_ID = "CLICK_LOCATION_LAYER_ID";
+ private MapView mapView;
+ private MapboxMap mapboxMap;
+ private SharedPreferences sharedPreferences;
+ private TextView longTextView;
+ private TextView latTextView;
+ private double savedLat;
+ private double savedLong;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
+
+ // Mapbox access token is configured here. This needs to be called either in your application
+ // object or in the same activity which contains the mapview.
+ Mapbox.getInstance(this, getString(R.string.access_token));
+
+ // This contains the MapView in XML and needs to be called after the access token is configured.
+ setContentView(R.layout.activity_lab_shared_preferences);
+
+ longTextView = findViewById(R.id.shared_pref_saved_long_textview);
+ latTextView = findViewById(R.id.shared_pref_saved_lat_textview);
+ longTextView.setText(String.format(getString(R.string.saved_long_textview), String.valueOf(0)));
+ latTextView.setText(String.format(getString(R.string.saved_lat_textview), String.valueOf(0)));
+
+ mapView = findViewById(R.id.mapView);
+ mapView.onCreate(savedInstanceState);
+ mapView.getMapAsync(this);
+ }
+
+ @Override
+ public void onMapReady(@NonNull MapboxMap mapboxMap) {
+ SharedPreferencesActivity.this.mapboxMap = mapboxMap;
+ mapboxMap.setStyle(
+
+ // Set the map to Mapbox's daytime traffic style
+ new Style.Builder().fromUri(Style.TRAFFIC_DAY)
+
+ // Add the SymbolLayer icon image to the map style
+ .withImage(CLICK_LOCATION_ICON_ID, BitmapFactory.decodeResource(
+ SharedPreferencesActivity.this.getResources(), R.drawable.red_marker))
+
+ // Adding a GeoJson source for the SymbolLayer icons.
+ .withSource(new GeoJsonSource(CLICK_LOCATION_SOURCE_ID))
+
+ // Adding the actual SymbolLayer to the map style. An offset is added that the bottom of the red
+ // marker icon gets fixed to the coordinate, rather than the middle of the icon being fixed to
+ // the coordinate point. This is offset is not always needed and is dependent on the image
+ // that you use for the SymbolLayer icon.
+ .withLayer(new SymbolLayer(CLICK_LOCATION_LAYER_ID, CLICK_LOCATION_SOURCE_ID)
+ .withProperties(PropertyFactory.iconImage(CLICK_LOCATION_ICON_ID),
+ iconAllowOverlap(true),
+ iconOffset(new Float[] {0f, -9f}))
+ ), new Style.OnStyleLoaded() {
+ @Override
+ public void onStyleLoaded(@NonNull Style style) {
+
+ mapboxMap.addOnMapClickListener(SharedPreferencesActivity.this);
+
+ // Get the coordinates from shared preferences
+ savedLong = getCoordinateFromSharedPref(SAVED_LONG_KEY);
+ savedLat = getCoordinateFromSharedPref(SAVED_LAT_KEY);
+
+ // Coordinates haven't been saved if both == 0
+ if (savedLong == 0 && savedLat == 0) {
+ Toast.makeText(SharedPreferencesActivity.this,
+ getString(R.string.tap_on_map_save_to_shared_pref), Toast.LENGTH_SHORT).show();
+
+ longTextView.setText(String.format(getString(R.string.saved_long_textview),
+ getString(R.string.not_saved_yet)));
+ latTextView.setText(String.format(getString(R.string.saved_lat_textview),
+ getString(R.string.not_saved_yet)));
+
+ } else {
+
+ // Move the camera to the previously-saved coordinates
+ mapboxMap.animateCamera(CameraUpdateFactory
+ .newCameraPosition(new CameraPosition.Builder()
+ .target(new LatLng(savedLat, savedLong))
+ .zoom(4)
+ .build()), 1200);
+
+ Toast.makeText(SharedPreferencesActivity.this,
+ getString(R.string.shared_pref_marker_placement), Toast.LENGTH_SHORT).show();
+
+ // Move the marker to the previously-saved coordinates
+ moveMarkerToLngLat(savedLong, savedLat);
+
+ longTextView.setText(String.format(
+ getString(R.string.saved_long_textview), String.valueOf(savedLong)));
+
+ latTextView.setText(String.format(
+ getString(R.string.saved_lat_textview), String.valueOf(savedLat)));
+ }
+ }
+ });
+ }
+
+ @Override
+ public boolean onMapClick(@NonNull LatLng mapClickPoint) {
+ double clickLatitude = mapClickPoint.getLatitude();
+ double clickLongitude = mapClickPoint.getLongitude();
+
+ longTextView.setText(String.format(
+ getString(R.string.saved_long_textview), String.valueOf(clickLongitude)));
+ latTextView.setText(String.format(
+ getString(R.string.saved_lat_textview), String.valueOf(clickLatitude)));
+
+ // Save the map click point coordinates to shared preferences
+ if (sharedPreferences != null) {
+ putCoordinateToSharedPref(SAVED_LAT_KEY, clickLatitude);
+ putCoordinateToSharedPref(SAVED_LONG_KEY, clickLongitude);
+ }
+
+ // Move the marker to the newly-saved coordinates
+ moveMarkerToLngLat(clickLongitude, clickLatitude);
+ return true;
+ }
+
+ /**
+ * Move the SymbolLayer icon to a new location
+ *
+ * @param newLong the new longitude
+ * @param newLat the new latitude
+ */
+ private void moveMarkerToLngLat(double newLong, double newLat) {
+ // Move and display the click center layer's red marker icon to
+ // wherever the map was clicked on
+ mapboxMap.getStyle(new Style.OnStyleLoaded() {
+ @Override
+ public void onStyleLoaded(@NonNull Style style) {
+ GeoJsonSource clickLocationSource = style.getSourceAs(CLICK_LOCATION_SOURCE_ID);
+ if (clickLocationSource != null) {
+ clickLocationSource.setGeoJson(Point.fromLngLat(newLong, newLat));
+ }
+ }
+ });
+ }
+
+ /**
+ * Save a specific number to shared preferences
+ *
+ * @param key the number's key
+ * @param value the actual number
+ */
+ private void putCoordinateToSharedPref(final String key, final double value) {
+ sharedPreferences.edit().putLong(key, Double.doubleToRawLongBits(value)).apply();
+ }
+
+ /**
+ * Retrieve a specific number from shared preferences
+ *
+ * @param key the key to use for retrieval
+ * @return the saved number
+ */
+ double getCoordinateFromSharedPref(final String key) {
+ return Double.longBitsToDouble(sharedPreferences.getLong(key, 0));
+ }
+
+ // Add the mapView lifecycle to the activity's lifecycle methods
+ @Override
+ public void onResume() {
+ super.onResume();
+ mapView.onResume();
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ mapView.onStart();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ mapView.onStop();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mapView.onPause();
+ }
+
+ @Override
+ public void onLowMemory() {
+ super.onLowMemory();
+ mapView.onLowMemory();
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (mapboxMap != null) {
+ mapboxMap.removeOnMapClickListener(this);
+ }
+ mapView.onDestroy();
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ mapView.onSaveInstanceState(outState);
+ }
+}
diff --git a/MapboxAndroidDemo/src/main/res/layout/activity_lab_shared_preferences.xml b/MapboxAndroidDemo/src/main/res/layout/activity_lab_shared_preferences.xml
new file mode 100644
index 000000000..ef3735f27
--- /dev/null
+++ b/MapboxAndroidDemo/src/main/res/layout/activity_lab_shared_preferences.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MapboxAndroidDemo/src/main/res/values/activity_strings.xml b/MapboxAndroidDemo/src/main/res/values/activity_strings.xml
index e2fca158a..3a0a3cfa8 100644
--- a/MapboxAndroidDemo/src/main/res/values/activity_strings.xml
+++ b/MapboxAndroidDemo/src/main/res/values/activity_strings.xml
@@ -453,4 +453,11 @@
Error with the request. Do you have internet access?
No features in the response.
%1$d Features in the API response: %2$s
+
+
+ Not saved yet
+ Saved latitude: %1$s
+ Saved longitude: %1$s
+ Tap on the map to save coordinates to the device\'s Shared Preferences
+ Marker placed at coordinates saved in Shared Preferences.
\ No newline at end of file
diff --git a/MapboxAndroidDemo/src/main/res/values/descriptions_strings.xml b/MapboxAndroidDemo/src/main/res/values/descriptions_strings.xml
index e8dd91783..248fc5aba 100644
--- a/MapboxAndroidDemo/src/main/res/values/descriptions_strings.xml
+++ b/MapboxAndroidDemo/src/main/res/values/descriptions_strings.xml
@@ -140,6 +140,7 @@
Quickly show the directions route associated with a RecyclerView item.
Use a ValueAnimator to adjust SymbolLayer icons\' rotation values and create a spinning effect.
Adjust the attribution "i" to match a map style, app UI, or color motif.
+ Use the Android system\'s Shared Preferences to save and retrieve coordinates.
Show an accurate and government-approved China map in your app using the Mapbox Maps SDK.
\ No newline at end of file
diff --git a/MapboxAndroidDemo/src/main/res/values/titles_strings.xml b/MapboxAndroidDemo/src/main/res/values/titles_strings.xml
index 637dafef4..a44f84996 100644
--- a/MapboxAndroidDemo/src/main/res/values/titles_strings.xml
+++ b/MapboxAndroidDemo/src/main/res/values/titles_strings.xml
@@ -139,4 +139,5 @@
RecyclerView Directions
Spinning icon
Style attribution
+ Shared preferences
diff --git a/MapboxAndroidDemo/src/main/res/values/urls_strings.xml b/MapboxAndroidDemo/src/main/res/values/urls_strings.xml
index 0b684f1f6..e0d8177bd 100644
--- a/MapboxAndroidDemo/src/main/res/values/urls_strings.xml
+++ b/MapboxAndroidDemo/src/main/res/values/urls_strings.xml
@@ -139,5 +139,6 @@
https://i.imgur.com/LurOuXQ.png
https://i.imgur.com/jxQpAt2.png
https://i.imgur.com/cGv98jb.png
+ https://i.imgur.com/znxAhDG.png
https://i.imgur.com/KwoEynZ.png