Static image notification
NOTE
This example is a part of the Mapbox Android Demo app. You can find the values for all referenced resources in the res
directory. For example, see res/values/activity_strings.xml
for R.string.*
references used in this example.
API pricing
Products used within the Mapbox Java SDK, including the Static Images API and the Tilequery API, are individually billed. For pricing information, see the documentation for the Static Images API and the Tilequery API.
<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:mapbox="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".examples.javaservices.StaticImageNotificationActivity"> <com.mapbox.mapboxsdk.maps.MapViewandroid:id="@+id/mapView"android:layout_width="match_parent"android:layout_height="match_parent"mapbox:mapbox_cameraTargetLat="40.729050870527914"mapbox:mapbox_cameraTargetLng="-73.9879401159224"mapbox:mapbox_cameraZoom="4" /> <LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:layout_gravity="top"android:layout_marginTop="24dp"android:orientation="horizontal"android:paddingStart="24dp"android:paddingLeft="24dp"android:paddingTop="24dp"android:paddingEnd="24dp"android:paddingRight="24dp"android:paddingBottom="10dp"> <TextViewandroid:id="@+id/tilequery_radius_value_textView"android:layout_width="45dp"android:layout_height="wrap_content"android:textColor="@color/white_pressed"tools:text="80 feet" /> <SeekBarandroid:id="@+id/tilequery_radius_seekbar"android:layout_width="match_parent"android:progress="250"android:thumbTint="@color/mapboxGreenDark"android:progressBackgroundTintMode="@color/mapboxGreenDark"android:progressTint="@color/mapboxGreenDark"android:max="500"android:layout_height="wrap_content" /> </LinearLayout> </FrameLayout>
package com.mapbox.mapboxandroiddemo.examples.javaservices; import android.app.Notification;import android.app.NotificationChannel;import android.app.NotificationManager;import android.content.Context;import android.content.Intent;import android.graphics.Bitmap;import android.graphics.Color;import android.graphics.drawable.Drawable;import android.os.Build;import android.os.Bundle;import android.widget.SeekBar;import android.widget.TextView;import android.widget.Toast; import com.mapbox.api.staticmap.v1.MapboxStaticMap;import com.mapbox.api.tilequery.MapboxTilequery;import com.mapbox.geojson.Feature;import com.mapbox.geojson.FeatureCollection;import com.mapbox.geojson.LineString;import com.mapbox.geojson.Point;import com.mapbox.mapboxandroiddemo.MainActivity;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.CircleLayer;import com.mapbox.mapboxsdk.style.layers.LineLayer;import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;import com.squareup.picasso.Picasso;import com.squareup.picasso.Target; import java.util.ArrayList;import java.util.List; import androidx.annotation.NonNull;import androidx.appcompat.app.AppCompatActivity;import androidx.core.app.NotificationCompat;import retrofit2.Call;import retrofit2.Callback;import retrofit2.Response;import timber.log.Timber; import static android.app.PendingIntent.getActivity;import static com.mapbox.mapboxsdk.style.layers.Property.NONE;import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE;import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleColor;import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleRadius;import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineColor;import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineWidth;import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility; /*** Use the Static Image API to create a Bitmap and then use the Bitmap in a notification.* Update the notification image and text as the map is tapped on. This example could also* be used with tracking the device location. For this, see* {@link com.mapbox.mapboxandroiddemo.examples.location.LocationChangeListeningActivity}*/public class StaticImageNotificationActivity extends AppCompatActivity implementsOnMapReadyCallback, MapboxMap.OnMapClickListener, SeekBar.OnSeekBarChangeListener { private static final String MAP_CLICK_CIRCLE_LAYER_SOURCE_ID = "map-click-circle-layer-source-id";private static final String WIFI_LINE_SOURCE_ID = "wifi-line-source-id";private static final String MAP_CLICK_CIRCLE_LAYER_ID = "map-click-circle-layer-id";private static final String WIFI_LINE_LAYER_ID = "wifi-line-layer-id";private static final String NOTIFICATION_CHANNEL_ID = "channel_id";private static final String STYLE_ID = "mapbox://styles/appsatmapboxcom/ck65durfd1j861iltx8v4gcm0";private static final String LINE_LAYER_COLOR = "#F13B6E";private static final float LINE_LAYER_WIDTH = 2;private static final double STATIC_IMAGE_ZOOM = 16.5;private static final int IMAGE_WIDTH = 400;private static final int IMAGE_HEIGHT = 400;private static final int NOTIFICATION_ID = 1002;private static final Point INITIAL_POINT = Point.fromLngLat(-73.9879401159224, 40.729050870527914);private MapView mapView;private MapboxMap mapboxMap;private NotificationManager notificationManager;private Target picassoTarget;private NotificationCompat.Builder builder;private Point lastMapClickPoint = INITIAL_POINT;private TextView tilequerySearchRadiusValueTextView;private boolean firstNotificationBuilt = false;private int tilequerySearchRadiusFeet = 250; @Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState); // 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_static_image_api_notification); initSearchRadiusSeekbar();tilequerySearchRadiusValueTextView = findViewById(R.id.tilequery_radius_value_textView);tilequerySearchRadiusValueTextView.setText(String.format(getString(R.string.static_image_api_notification_seekbar_feet), tilequerySearchRadiusFeet)); mapView = findViewById(R.id.mapView);mapView.onCreate(savedInstanceState); // Set a callback for when MapboxMap is ready to be usedmapView.getMapAsync(this);} private void initSearchRadiusSeekbar() {final SeekBar radiusSeekbar = findViewById(R.id.tilequery_radius_seekbar);radiusSeekbar.setProgress(tilequerySearchRadiusFeet);radiusSeekbar.setMax(tilequerySearchRadiusFeet * 2);radiusSeekbar.setOnSeekBarChangeListener(this);} private void updateUiBasedOnSeekbarMovement(int progress) {tilequerySearchRadiusFeet = progress;tilequerySearchRadiusValueTextView.setText(String.format(getString(R.string.static_image_api_notification_seekbar_feet), progress));} @Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {updateUiBasedOnSeekbarMovement(progress);} @Overridepublic void onStartTrackingTouch(SeekBar seekBar) { } @Overridepublic void onStopTrackingTouch(SeekBar seekBar) {updateUiBasedOnSeekbarMovement(seekBar.getProgress());queryWifiSpotsWithTilequeryApi(new LatLng(lastMapClickPoint.latitude(), lastMapClickPoint.longitude()));} @Overridepublic void onMapReady(@NonNull final MapboxMap mapboxMap) {StaticImageNotificationActivity.this.mapboxMap = mapboxMap;mapboxMap.setStyle(new Style.Builder().fromUri(STYLE_ID), new Style.OnStyleLoaded() {@Overridepublic void onStyleLoaded(@NonNull Style style) {initMapClickCircleLayer();initWifiLineLayer();mapboxMap.addOnMapClickListener(StaticImageNotificationActivity.this);queryWifiSpotsWithTilequeryApi(new LatLng(INITIAL_POINT.latitude(), INITIAL_POINT.longitude()));Toast.makeText(StaticImageNotificationActivity.this,getString(R.string.click_on_map_instruction), Toast.LENGTH_SHORT).show();mapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder().zoom(16).build()), 5000);}});} /*** Adjust various UI and make required API calls when the map is tapped on** @param mapClickPoint where the map was tapped on* @return boolean. True if this click should be consumed and not passed further to other* listeners registered afterwards, false otherwise.*/@Overridepublic boolean onMapClick(@NonNull LatLng mapClickPoint) {// Update the map click point circle's locationmapboxMap.getStyle(new Style.OnStyleLoaded() {@Overridepublic void onStyleLoaded(@NonNull Style style) {lastMapClickPoint = Point.fromLngLat(mapClickPoint.getLongitude(), mapClickPoint.getLatitude()); GeoJsonSource deviceLocationSource = style.getSourceAs(MAP_CLICK_CIRCLE_LAYER_SOURCE_ID);if (deviceLocationSource != null) {deviceLocationSource.setGeoJson(Point.fromLngLat(mapClickPoint.getLongitude(), mapClickPoint.getLatitude()));}queryWifiSpotsWithTilequeryApi(mapClickPoint);}});return true;} /*** Creates bitmap from given parameters, and creates a notification with that bitmap** @param staticImageCenterLatLng coordinates for center of static image*/private void getStaticImageFromApi(LatLng staticImageCenterLatLng, Integer wifiLocationsNearby,String closestWifiLocation) {mapboxMap.getStyle(new Style.OnStyleLoaded() {@Overridepublic void onStyleLoaded(@NonNull Style style) {picassoTarget = new Target() {@Overridepublic void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {if (!firstNotificationBuilt) {createNotification(bitmap, wifiLocationsNearby, closestWifiLocation);} else {updateNotification(bitmap, wifiLocationsNearby, closestWifiLocation);}} @Overridepublic void onBitmapFailed(Drawable errorDrawable) {Toast.makeText(StaticImageNotificationActivity.this,R.string.static_image_api_notification_bitmap_fail, Toast.LENGTH_SHORT).show();} @Overridepublic void onPrepareLoad(Drawable placeHolderDrawable) {}}; Picasso.with(StaticImageNotificationActivity.this).load(buildStaticImageUrl(staticImageCenterLatLng)).into(picassoTarget);}});} /*** Build a URL to request an image from the Mapbox Static Image API** @param staticImageCenterLatLng the coordinates that the image should be centered on* @return a built and valid URL for the Mapbox Static Image API*/private String buildStaticImageUrl(LatLng staticImageCenterLatLng) {return MapboxStaticMap.builder().accessToken(getString(R.string.access_token)) // Customer use String is needed because a non-Mapbox default style ID is being used.user("appsatmapboxcom") /*Custom style ID is needed because this examples uses a custom stylerather than a default Mapbox style. If a default Mapbox style were used,a constant string from the StaticMapCriteria class, could be passed throughinstead*/.styleId("ck65durfd1j861iltx8v4gcm0") .cameraPoint(Point.fromLngLat(staticImageCenterLatLng.getLongitude(), staticImageCenterLatLng.getLatitude())).cameraZoom(STATIC_IMAGE_ZOOM).width(IMAGE_WIDTH).height(IMAGE_HEIGHT).retina(true).build().url().toString();} /*** Creates a notification with given bitmap as a large icon** @param bitmap to add to the notification* @param wifiLocationsNearby the number of wifi locations as determined by the Tilequery API*/private void createNotification(Bitmap bitmap, Integer wifiLocationsNearby, String closestWifiLocationAddressText) {if (notificationManager == null) {notificationManager =(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);}if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {if (notificationManager != null) {NotificationChannel notificationChannel = notificationManager.getNotificationChannel(NOTIFICATION_CHANNEL_ID);if (notificationChannel == null) {notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID,"channel_name", NotificationManager.IMPORTANCE_HIGH);notificationChannel.setDescription("channel_description");notificationManager.createNotificationChannel(notificationChannel);}}}Intent intent = new Intent(this, MainActivity.class).setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);builder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID).setContentTitle(String.format(getString(R.string.static_image_api_notification_content_title),wifiLocationsNearby, tilequerySearchRadiusFeet)).setSmallIcon(R.drawable.mapbox_logo_icon).setContentText(String.format(getString(R.string.static_image_api_notification_description),closestWifiLocationAddressText)).setContentIntent(getActivity(this, 0, intent, 0)).setLargeIcon(bitmap).setStyle(new NotificationCompat.BigPictureStyle().bigPicture(bitmap).bigLargeIcon(null));Notification notification = builder.build();notificationManager.notify(NOTIFICATION_ID, notification);firstNotificationBuilt = true;} /*** Update an existing notification with a new image and text** @param newBitmapFromStaticImageApi to add to the notification* @param wifiLocationsNearby the number of wifi locations as determined by the Tilequery API*/private void updateNotification(Bitmap newBitmapFromStaticImageApi, Integer wifiLocationsNearby,String closestWifiLocationAddressText) { builder.setLargeIcon(newBitmapFromStaticImageApi);builder.setStyle(new NotificationCompat.BigPictureStyle().bigPicture(newBitmapFromStaticImageApi).bigLargeIcon(null));builder.setContentTitle(String.format(getString(R.string.static_image_api_notification_content_title),wifiLocationsNearby, tilequerySearchRadiusFeet));builder.setContentText(String.format(getString(R.string.static_image_api_notification_description),closestWifiLocationAddressText));notificationManager.notify(NOTIFICATION_ID, builder.build());} /*** Add the CircleLayer to add a circle that represents a certain location. In this example,* the circle is moved by tapping somewhere else on the map.* Do note that this setup is only for the purposes of this specific example. A real world alternative* is for the circle to be replaced by the {@link com.mapbox.mapboxsdk.location.LocationComponent}.* <p>* See {@link com.mapbox.mapboxandroiddemo.examples.location.LocationChangeListeningActivity}* to see how actual device location changes can be listened to.*/private void initMapClickCircleLayer() {mapboxMap.getStyle(new Style.OnStyleLoaded() {@Overridepublic void onStyleLoaded(@NonNull Style style) {style.addSource(new GeoJsonSource(MAP_CLICK_CIRCLE_LAYER_SOURCE_ID, INITIAL_POINT));CircleLayer mapClickPointLocationCircleLayer = new CircleLayer(MAP_CLICK_CIRCLE_LAYER_ID,MAP_CLICK_CIRCLE_LAYER_SOURCE_ID).withProperties(circleColor(Color.parseColor("#F13B6E")),circleRadius(6.6f));style.addLayer(mapClickPointLocationCircleLayer);}});} /*** Add the LineLayer to draw small lines from the map click point to the wifi locations* found by the Tilequery API*/private void initWifiLineLayer() {mapboxMap.getStyle(new Style.OnStyleLoaded() {@Overridepublic void onStyleLoaded(@NonNull Style style) {style.addSource(new GeoJsonSource(WIFI_LINE_SOURCE_ID));LineLayer wifiLineLayer = new LineLayer(WIFI_LINE_LAYER_ID,WIFI_LINE_SOURCE_ID).withProperties(lineColor(Color.parseColor(LINE_LAYER_COLOR)),lineWidth(LINE_LAYER_WIDTH));if (style.getLayer("wifi-hotspot-locations") != null) {style.addLayerBelow(wifiLineLayer, "wifi-hotspot-locations");} else {style.addLayer(wifiLineLayer);}}});} /*** Use the Java SDK's MapboxTilequery class to build a API request and use the API response** @param clickPoint the center point that the the tilequery will originate from.*/private void queryWifiSpotsWithTilequeryApi(@NonNull LatLng clickPoint) {MapboxTilequery.builder().accessToken(getString(R.string.access_token)).tilesetIds("appsatmapboxcom.bml2ioc4").query(Point.fromLngLat(clickPoint.getLongitude(), clickPoint.getLatitude())).radius(tilequerySearchRadiusFeet / 3).geometry("point").layers("NYC_Wi-Fi_Hotspot_Locations-8qwm7n").build().enqueueCall(new Callback<FeatureCollection>() {@Overridepublic void onResponse(Call<FeatureCollection> call, Response<FeatureCollection> response) {if (response.body() != null) {FeatureCollection responseFeatureCollection = response.body();mapboxMap.getStyle(new Style.OnStyleLoaded() {@Overridepublic void onStyleLoaded(@NonNull Style style) {if (responseFeatureCollection.features() != null) {List<Feature> responseFeatureList = responseFeatureCollection.features();GeoJsonSource wifiLineSource = style.getSourceAs(WIFI_LINE_SOURCE_ID); LineLayer nearbyLineLayer = style.getLayerAs(WIFI_LINE_LAYER_ID); if (responseFeatureList.isEmpty()) {Toast.makeText(StaticImageNotificationActivity.this,getString(R.string.static_image_api_notification_no_wifi_nearby),Toast.LENGTH_SHORT).show(); if (nearbyLineLayer != null) {if (VISIBLE.equals(nearbyLineLayer.getVisibility().getValue())) {nearbyLineLayer.setProperties(visibility(NONE));}} } else {if (nearbyLineLayer != null) {if (NONE.equals(nearbyLineLayer.getVisibility().getValue())) {nearbyLineLayer.setProperties(visibility(VISIBLE));}if (wifiLineSource != null) {drawLinesFromClickPointToNearbyWifi(responseFeatureList, wifiLineSource);}} getStaticImageFromApi(new LatLng(clickPoint.getLatitude(), clickPoint.getLongitude()),responseFeatureList.size(), responseFeatureList.get(0).getStringProperty("location").toLowerCase()); }}}});}} @Overridepublic void onFailure(Call<FeatureCollection> call, Throwable throwable) {Timber.d("Request failed: %s", throwable.getMessage());Toast.makeText(StaticImageNotificationActivity.this, R.string.api_error,Toast.LENGTH_SHORT).show();}});} /*** Draws a line from the click point to each of the wifi locations that were identified by the* Tilequery API query** @param featureList the feature list returned by the Tilequery API repsonse object* @param wifiLineSource the source used by the LineLayer*/private void drawLinesFromClickPointToNearbyWifi(List<Feature> featureList, GeoJsonSource wifiLineSource) { List<Feature> lineFeatureList = new ArrayList<>(); for (Feature singleFeature : featureList) {List<Point> singleLineStringPointList = new ArrayList<>(); // Cast the Tilequery response Feature to a PointPoint singleFeaturePoint = (Point) singleFeature.geometry(); // Add the Point to the Point listsingleLineStringPointList.add(singleFeaturePoint); // Add the last map click Point to the Point listsingleLineStringPointList.add(lastMapClickPoint); // Create a Feature from the LineString and add the Feature to the// Feature list.LineString singleLineString = LineString.fromLngLats(singleLineStringPointList); lineFeatureList.add(Feature.fromGeometry(singleLineString));} // Use the Feature list to create a FeatureCollection and update// the LineLayer source with the FeatureCollectionif (wifiLineSource != null) {wifiLineSource.setGeoJson(FeatureCollection.fromFeatures(lineFeatureList));}} // Add the mapView lifecycle to the activity's lifecycle methods@Overridepublic void onResume() {super.onResume();mapView.onResume();} @Overrideprotected void onStart() {super.onStart();mapView.onStart();} @Overrideprotected void onStop() {super.onStop();mapView.onStop();} @Overridepublic void onPause() {super.onPause();mapView.onPause();} @Overridepublic void onSaveInstanceState(Bundle outState) {super.onSaveInstanceState(outState);mapView.onSaveInstanceState(outState);} @Overridepublic void onLowMemory() {super.onLowMemory();mapView.onLowMemory();} @Overrideprotected void onDestroy() {Picasso.with(this).cancelRequest(picassoTarget);if (mapboxMap != null) {mapboxMap.removeOnMapClickListener(this);}mapView.onDestroy();super.onDestroy();}}
Was this example helpful?