[build] - initial commit

This commit is contained in:
tobrun
2019-10-09 13:19:56 +02:00
commit a3ef1ac2d0
1061 changed files with 403354 additions and 0 deletions

View File

@@ -0,0 +1,95 @@
package com.mapbox.mapboxsdk.testapp;
import android.app.Application;
import android.os.StrictMode;
import android.text.TextUtils;
import com.mapbox.mapboxsdk.MapStrictMode;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.log.Logger;
import com.mapbox.mapboxsdk.maps.TelemetryDefinition;
import com.mapbox.mapboxsdk.testapp.utils.TileLoadingMeasurementUtils;
import com.mapbox.mapboxsdk.testapp.utils.TimberLogger;
import com.mapbox.mapboxsdk.testapp.utils.TokenUtils;
import com.squareup.leakcanary.LeakCanary;
import timber.log.Timber;
import static timber.log.Timber.DebugTree;
/**
* Application class of the test application.
* <p>
* Initialises components as LeakCanary, Strictmode, Timber and Mapbox
* </p>
*/
public class MapboxApplication extends Application {
private static final String DEFAULT_MAPBOX_ACCESS_TOKEN = "YOUR_MAPBOX_ACCESS_TOKEN_GOES_HERE";
private static final String ACCESS_TOKEN_NOT_SET_MESSAGE = "In order to run the Test App you need to set a valid "
+ "access token. During development, you can set the MAPBOX_ACCESS_TOKEN environment variable for the SDK to "
+ "automatically include it in the Test App. Otherwise, you can manually include it in the "
+ "res/values/developer-config.xml file in the MapboxGLAndroidSDKTestApp folder.";
@Override
public void onCreate() {
super.onCreate();
if (!initializeLeakCanary()) {
return;
}
initializeLogger();
initializeStrictMode();
initializeMapbox();
}
protected boolean initializeLeakCanary() {
if (LeakCanary.isInAnalyzerProcess(this)) {
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
return false;
}
LeakCanary.install(this);
return true;
}
private void initializeLogger() {
Logger.setLoggerDefinition(new TimberLogger());
if (BuildConfig.DEBUG) {
Timber.plant(new DebugTree());
}
}
private void initializeStrictMode() {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
.detectDiskReads()
.detectDiskWrites()
.detectNetwork()
.penaltyLog()
.build());
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects()
.penaltyLog()
.penaltyDeath()
.build());
}
private void initializeMapbox() {
String accessToken = TokenUtils.getMapboxAccessToken(getApplicationContext());
validateAccessToken(accessToken);
Mapbox.getInstance(getApplicationContext(), accessToken);
TelemetryDefinition telemetry = Mapbox.getTelemetry();
if (telemetry == null) {
throw new IllegalStateException("Telemetry was unavailable during test application start.");
}
telemetry.setDebugLoggingEnabled(true);
TileLoadingMeasurementUtils.setUpTileLoadingMeasurement();
MapStrictMode.setStrictModeEnabled(true);
}
private static void validateAccessToken(String accessToken) {
if (TextUtils.isEmpty(accessToken) || accessToken.equals(DEFAULT_MAPBOX_ACCESS_TOKEN)) {
Timber.e(ACCESS_TOKEN_NOT_SET_MESSAGE);
}
}
}

View File

@@ -0,0 +1,168 @@
package com.mapbox.mapboxsdk.testapp.activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.StringRes;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.adapter.FeatureAdapter;
import com.mapbox.mapboxsdk.testapp.adapter.FeatureSectionAdapter;
import com.mapbox.mapboxsdk.testapp.model.activity.Feature;
import com.mapbox.mapboxsdk.testapp.utils.ItemClickSupport;
import timber.log.Timber;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* Activity shown when application is started
* <p>
* This activity will generate data for RecyclerView based on the AndroidManifest entries.
* It uses tags as category and description to order the different entries.
* </p>
*/
public class FeatureOverviewActivity extends AppCompatActivity {
private static final String KEY_STATE_FEATURES = "featureList";
private RecyclerView recyclerView;
private FeatureSectionAdapter sectionAdapter;
private List<Feature> features;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_feature_overview);
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener());
recyclerView.setHasFixedSize(true);
ItemClickSupport.addTo(recyclerView).setOnItemClickListener((recyclerView, position, view) -> {
if (!sectionAdapter.isSectionHeaderPosition(position)) {
int itemPosition = sectionAdapter.getConvertedPosition(position);
Feature feature = features.get(itemPosition);
startFeature(feature);
}
});
if (savedInstanceState == null) {
loadFeatures();
} else {
features = savedInstanceState.getParcelableArrayList(KEY_STATE_FEATURES);
onFeaturesLoaded(features);
}
}
private void loadFeatures() {
try {
new LoadFeatureTask().execute(
getPackageManager().getPackageInfo(getPackageName(),
PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA));
} catch (PackageManager.NameNotFoundException exception) {
Timber.e(exception, "Could not resolve package info");
}
}
private void onFeaturesLoaded(List<Feature> featuresList) {
features = featuresList;
if (featuresList == null || featuresList.isEmpty()) {
return;
}
List<FeatureSectionAdapter.Section> sections = new ArrayList<>();
String currentCat = "";
for (int i = 0; i < features.size(); i++) {
String category = features.get(i).getCategory();
if (!currentCat.equals(category)) {
sections.add(new FeatureSectionAdapter.Section(i, category));
currentCat = category;
}
}
FeatureSectionAdapter.Section[] dummy = new FeatureSectionAdapter.Section[sections.size()];
sectionAdapter = new FeatureSectionAdapter(
this, R.layout.section_main_layout, R.id.section_text, new FeatureAdapter(features));
sectionAdapter.setSections(sections.toArray(dummy));
recyclerView.setAdapter(sectionAdapter);
}
private void startFeature(Feature feature) {
Intent intent = new Intent();
intent.setComponent(new ComponentName(getPackageName(), feature.getName()));
startActivity(intent);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelableArrayList(KEY_STATE_FEATURES, (ArrayList<Feature>) features);
}
private class LoadFeatureTask extends AsyncTask<PackageInfo, Void, List<Feature>> {
@Override
protected List<Feature> doInBackground(PackageInfo... params) {
List<Feature> features = new ArrayList<>();
PackageInfo app = params[0];
String packageName = getApplicationContext().getPackageName();
String metaDataKey = getString(R.string.category);
for (ActivityInfo info : app.activities) {
if (info.labelRes != 0 && info.name.startsWith(packageName)
&& !info.name.equals(FeatureOverviewActivity.class.getName())) {
String label = getString(info.labelRes);
String description = resolveString(info.descriptionRes);
String category = resolveMetaData(info.metaData, metaDataKey);
features.add(new Feature(info.name, label, description, category));
}
}
if (!features.isEmpty()) {
Comparator<Feature> comparator = (lhs, rhs) -> {
int result = lhs.getCategory().compareToIgnoreCase(rhs.getCategory());
if (result == 0) {
result = lhs.getLabel().compareToIgnoreCase(rhs.getLabel());
}
return result;
};
Collections.sort(features, comparator);
}
return features;
}
private String resolveMetaData(Bundle bundle, String key) {
String category = null;
if (bundle != null) {
category = bundle.getString(key);
}
return category;
}
private String resolveString(@StringRes int stringRes) {
try {
return getString(stringRes);
} catch (Resources.NotFoundException exception) {
return "-";
}
}
@Override
protected void onPostExecute(List<Feature> features) {
super.onPostExecute(features);
onFeaturesLoaded(features);
}
}
}

View File

@@ -0,0 +1,443 @@
package com.mapbox.mapboxsdk.testapp.activity.annotation;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.LinearInterpolator;
import com.google.gson.JsonObject;
import com.mapbox.geojson.Feature;
import com.mapbox.geojson.FeatureCollection;
import com.mapbox.geojson.Point;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.style.layers.SymbolLayer;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.turf.TurfMeasurement;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import static com.mapbox.mapboxsdk.style.expressions.Expression.get;
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;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconRotate;
/**
* Test activity showcasing animating a SymbolLayer.
*/
public class AnimatedSymbolLayerActivity extends AppCompatActivity {
private static final String PASSENGER = "passenger";
private static final String PASSENGER_LAYER = "passenger-layer";
private static final String PASSENGER_SOURCE = "passenger-source";
private static final String TAXI = "taxi";
private static final String TAXI_LAYER = "taxi-layer";
private static final String TAXI_SOURCE = "taxi-source";
private static final String RANDOM_CAR_LAYER = "random-car-layer";
private static final String RANDOM_CAR_SOURCE = "random-car-source";
private static final String RANDOM_CAR_IMAGE_ID = "random-car";
private static final String PROPERTY_BEARING = "bearing";
private static final String WATERWAY_LAYER_ID = "waterway-label";
private static final int DURATION_RANDOM_MAX = 1500;
private static final int DURATION_BASE = 3000;
private final Random random = new Random();
private MapView mapView;
private MapboxMap mapboxMap;
private Style style;
private List<Car> randomCars = new ArrayList<>();
private GeoJsonSource randomCarSource;
private Car taxi;
private GeoJsonSource taxiSource;
private LatLng passenger;
private List<Animator> animators = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_animated_marker);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(map -> {
this.mapboxMap = map;
map.setStyle(Style.MAPBOX_STREETS, style -> {
this.style = style;
setupCars();
animateRandomRoutes();
animateTaxi();
});
});
}
private void setupCars() {
addRandomCars();
addPassenger();
addMainCar();
}
private void animateRandomRoutes() {
final Car longestDrive = getLongestDrive();
final Random random = new Random();
for (final Car car : randomCars) {
final boolean isLongestDrive = longestDrive.equals(car);
ValueAnimator valueAnimator = ValueAnimator.ofObject(new LatLngEvaluator(), car.current, car.next);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
private LatLng latLng;
@Override
public void onAnimationUpdate(ValueAnimator animation) {
latLng = (LatLng) animation.getAnimatedValue();
car.current = latLng;
if (isLongestDrive) {
updateRandomCarSource();
}
}
});
if (isLongestDrive) {
valueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
updateRandomDestinations();
animateRandomRoutes();
}
});
}
valueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
car.feature.properties().addProperty("bearing", Car.getBearing(car.current, car.next));
}
});
int offset = random.nextInt(2) == 0 ? 0 : random.nextInt(1000) + 250;
valueAnimator.setStartDelay(offset);
valueAnimator.setDuration(car.duration - offset);
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.start();
animators.add(valueAnimator);
}
}
private void animateTaxi() {
ValueAnimator valueAnimator = ValueAnimator.ofObject(new LatLngEvaluator(), taxi.current, taxi.next);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
private LatLng latLng;
@Override
public void onAnimationUpdate(ValueAnimator animation) {
latLng = (LatLng) animation.getAnimatedValue();
taxi.current = latLng;
updateTaxiSource();
}
});
valueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
updatePassenger();
animateTaxi();
}
});
valueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
taxi.feature.properties().addProperty("bearing", Car.getBearing(taxi.current, taxi.next));
}
});
valueAnimator.setDuration((long) (7 * taxi.current.distanceTo(taxi.next)));
valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
valueAnimator.start();
animators.add(valueAnimator);
}
private void updatePassenger() {
passenger = getLatLngInBounds();
updatePassengerSource();
taxi.setNext(passenger);
}
private void updatePassengerSource() {
GeoJsonSource source = style.getSourceAs(PASSENGER_SOURCE);
FeatureCollection featureCollection = FeatureCollection.fromFeatures(new Feature[] {
Feature.fromGeometry(
Point.fromLngLat(
passenger.getLongitude(),
passenger.getLatitude()
)
)
});
source.setGeoJson(featureCollection);
}
private void updateTaxiSource() {
taxi.updateFeature();
taxiSource.setGeoJson(taxi.feature);
}
private void updateRandomDestinations() {
for (Car randomCar : randomCars) {
randomCar.setNext(getLatLngInBounds());
}
}
private Car getLongestDrive() {
Car longestDrive = null;
for (Car randomCar : randomCars) {
if (longestDrive == null) {
longestDrive = randomCar;
} else if (longestDrive.duration < randomCar.duration) {
longestDrive = randomCar;
}
}
return longestDrive;
}
private void updateRandomCarSource() {
for (Car randomCarsRoute : randomCars) {
randomCarsRoute.updateFeature();
}
randomCarSource.setGeoJson(featuresFromRoutes());
}
private FeatureCollection featuresFromRoutes() {
List<Feature> features = new ArrayList<>();
for (Car randomCarsRoute : randomCars) {
features.add(randomCarsRoute.feature);
}
return FeatureCollection.fromFeatures(features);
}
private long getDuration() {
return random.nextInt(DURATION_RANDOM_MAX) + DURATION_BASE;
}
private void addRandomCars() {
LatLng latLng;
LatLng next;
for (int i = 0; i < 10; i++) {
latLng = getLatLngInBounds();
next = getLatLngInBounds();
JsonObject properties = new JsonObject();
properties.addProperty(PROPERTY_BEARING, Car.getBearing(latLng, next));
Feature feature = Feature.fromGeometry(
Point.fromLngLat(
latLng.getLongitude(),
latLng.getLatitude()
), properties);
randomCars.add(
new Car(feature, next, getDuration())
);
}
randomCarSource = new GeoJsonSource(RANDOM_CAR_SOURCE, featuresFromRoutes());
style.addSource(randomCarSource);
style.addImage(RANDOM_CAR_IMAGE_ID,
((BitmapDrawable) getResources().getDrawable(R.drawable.ic_car_top)).getBitmap());
SymbolLayer symbolLayer = new SymbolLayer(RANDOM_CAR_LAYER, RANDOM_CAR_SOURCE);
symbolLayer.withProperties(
iconImage(RANDOM_CAR_IMAGE_ID),
iconAllowOverlap(true),
iconRotate(get(PROPERTY_BEARING)),
iconIgnorePlacement(true)
);
style.addLayerBelow(symbolLayer, WATERWAY_LAYER_ID);
}
private void addPassenger() {
passenger = getLatLngInBounds();
FeatureCollection featureCollection = FeatureCollection.fromFeatures(new Feature[] {
Feature.fromGeometry(
Point.fromLngLat(
passenger.getLongitude(),
passenger.getLatitude()
)
)
});
style.addImage(PASSENGER,
((BitmapDrawable) getResources().getDrawable(R.drawable.icon_burned)).getBitmap());
GeoJsonSource geoJsonSource = new GeoJsonSource(PASSENGER_SOURCE, featureCollection);
style.addSource(geoJsonSource);
SymbolLayer symbolLayer = new SymbolLayer(PASSENGER_LAYER, PASSENGER_SOURCE);
symbolLayer.withProperties(
iconImage(PASSENGER),
iconIgnorePlacement(true),
iconAllowOverlap(true)
);
style.addLayerBelow(symbolLayer, RANDOM_CAR_LAYER);
}
private void addMainCar() {
LatLng latLng = getLatLngInBounds();
JsonObject properties = new JsonObject();
properties.addProperty(PROPERTY_BEARING, Car.getBearing(latLng, passenger));
Feature feature = Feature.fromGeometry(
Point.fromLngLat(
latLng.getLongitude(),
latLng.getLatitude()), properties);
FeatureCollection featureCollection = FeatureCollection.fromFeatures(new Feature[] {feature});
taxi = new Car(feature, passenger, getDuration());
style.addImage(TAXI,
((BitmapDrawable) getResources().getDrawable(R.drawable.ic_taxi_top)).getBitmap());
taxiSource = new GeoJsonSource(TAXI_SOURCE, featureCollection);
style.addSource(taxiSource);
SymbolLayer symbolLayer = new SymbolLayer(TAXI_LAYER, TAXI_SOURCE);
symbolLayer.withProperties(
iconImage(TAXI),
iconRotate(get(PROPERTY_BEARING)),
iconAllowOverlap(true),
iconIgnorePlacement(true)
);
style.addLayer(symbolLayer);
}
private LatLng getLatLngInBounds() {
LatLngBounds bounds = mapboxMap.getProjection().getVisibleRegion().latLngBounds;
Random generator = new Random();
double randomLat = bounds.getLatSouth() + generator.nextDouble()
* (bounds.getLatNorth() - bounds.getLatSouth());
double randomLon = bounds.getLonWest() + generator.nextDouble()
* (bounds.getLonEast() - bounds.getLonWest());
return new LatLng(randomLat, randomLon);
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
for (Animator animator : animators) {
if (animator != null) {
animator.removeAllListeners();
animator.cancel();
}
}
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
/**
* Evaluator for LatLng pairs
*/
private static class LatLngEvaluator implements TypeEvaluator<LatLng> {
private LatLng latLng = new LatLng();
@Override
public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) {
latLng.setLatitude(startValue.getLatitude()
+ ((endValue.getLatitude() - startValue.getLatitude()) * fraction));
latLng.setLongitude(startValue.getLongitude()
+ ((endValue.getLongitude() - startValue.getLongitude()) * fraction));
return latLng;
}
}
private static class Car {
private Feature feature;
private LatLng next;
private LatLng current;
private long duration;
Car(Feature feature, LatLng next, long duration) {
this.feature = feature;
Point point = ((Point) feature.geometry());
this.current = new LatLng(point.latitude(), point.longitude());
this.duration = duration;
this.next = next;
}
void setNext(LatLng next) {
this.next = next;
}
void updateFeature() {
feature = Feature.fromGeometry(Point.fromLngLat(
current.getLongitude(),
current.getLatitude())
);
feature.properties().addProperty("bearing", getBearing(current, next));
}
private static float getBearing(LatLng from, LatLng to) {
return (float) TurfMeasurement.bearing(
Point.fromLngLat(from.getLongitude(), from.getLatitude()),
Point.fromLngLat(to.getLongitude(), to.getLatitude())
);
}
}
}

View File

@@ -0,0 +1,200 @@
package com.mapbox.mapboxsdk.testapp.activity.annotation;
import android.app.ProgressDialog;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
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.Style;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.utils.GeoParseUtil;
import timber.log.Timber;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* Test activity showcasing adding a large amount of Markers.
*/
public class BulkMarkerActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener {
private MapboxMap mapboxMap;
private MapView mapView;
private List<LatLng> locations;
private ProgressDialog progressDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_marker_bulk);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this::initMap);
}
private void initMap(MapboxMap mapboxMap) {
this.mapboxMap = mapboxMap;
mapboxMap.setStyle(Style.MAPBOX_STREETS);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
ArrayAdapter<CharSequence> spinnerAdapter = ArrayAdapter.createFromResource(
this, R.array.bulk_marker_list, android.R.layout.simple_spinner_item);
spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
getMenuInflater().inflate(R.menu.menu_bulk_marker, menu);
MenuItem item = menu.findItem(R.id.spinner);
Spinner spinner = (Spinner) MenuItemCompat.getActionView(item);
spinner.setAdapter(spinnerAdapter);
spinner.setOnItemSelectedListener(BulkMarkerActivity.this);
return true;
}
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
int amount = Integer.valueOf(getResources().getStringArray(R.array.bulk_marker_list)[position]);
if (locations == null) {
progressDialog = ProgressDialog.show(this, "Loading", "Fetching markers", false);
new LoadLocationTask(this, amount).execute();
} else {
showMarkers(amount);
}
}
private void onLatLngListLoaded(List<LatLng> latLngs, int amount) {
progressDialog.hide();
locations = latLngs;
showMarkers(amount);
}
private void showMarkers(int amount) {
if (mapboxMap == null || locations == null || mapView.isDestroyed()) {
return;
}
mapboxMap.clear();
if (locations.size() < amount) {
amount = locations.size();
}
showGlMarkers(amount);
}
private void showGlMarkers(int amount) {
List<MarkerOptions> markerOptionsList = new ArrayList<>();
DecimalFormat formatter = new DecimalFormat("#.#####");
Random random = new Random();
int randomIndex;
for (int i = 0; i < amount; i++) {
randomIndex = random.nextInt(locations.size());
LatLng latLng = locations.get(randomIndex);
markerOptionsList.add(new MarkerOptions()
.position(latLng)
.title(String.valueOf(i))
.snippet(formatter.format(latLng.getLatitude()) + ", " + formatter.format(latLng.getLongitude())));
}
mapboxMap.addMarkers(markerOptionsList);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
// nothing selected, nothing to do!
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
private static class LoadLocationTask extends AsyncTask<Void, Integer, List<LatLng>> {
private WeakReference<BulkMarkerActivity> activity;
private int amount;
private LoadLocationTask(BulkMarkerActivity activity, int amount) {
this.amount = amount;
this.activity = new WeakReference<>(activity);
}
@Override
protected List<LatLng> doInBackground(Void... params) {
BulkMarkerActivity activity = this.activity.get();
if (activity != null) {
String json = null;
try {
json = GeoParseUtil.loadStringFromAssets(activity.getApplicationContext(), "points.geojson");
} catch (IOException exception) {
Timber.e(exception, "Could not add markers");
}
if (json != null) {
return GeoParseUtil.parseGeoJsonCoordinates(json);
}
}
return null;
}
@Override
protected void onPostExecute(List<LatLng> locations) {
super.onPostExecute(locations);
BulkMarkerActivity activity = this.activity.get();
if (activity != null) {
activity.onLatLngListLoaded(locations, amount);
}
}
}
}

View File

@@ -0,0 +1,120 @@
package com.mapbox.mapboxsdk.testapp.activity.annotation;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.res.ResourcesCompat;
import android.support.v7.app.AppCompatActivity;
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.Style;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.utils.IconUtils;
/**
* Test activity showcasing updating a Marker position, title, icon and snippet.
*/
public class DynamicMarkerChangeActivity extends AppCompatActivity {
private static final LatLng LAT_LNG_CHELSEA = new LatLng(51.481670, -0.190849);
private static final LatLng LAT_LNG_ARSENAL = new LatLng(51.555062, -0.108417);
private MapView mapView;
private MapboxMap mapboxMap;
private Marker marker;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dynamic_marker);
mapView = findViewById(R.id.mapView);
mapView.setTag(false);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(mapboxMap -> {
mapboxMap.setStyle(Style.MAPBOX_STREETS);
DynamicMarkerChangeActivity.this.mapboxMap = mapboxMap;
// Create marker
MarkerOptions markerOptions = new MarkerOptions()
.position(LAT_LNG_CHELSEA)
.icon(IconUtils.drawableToIcon(DynamicMarkerChangeActivity.this, R.drawable.ic_stars,
ResourcesCompat.getColor(getResources(), R.color.blueAccent, getTheme())))
.title(getString(R.string.dynamic_marker_chelsea_title))
.snippet(getString(R.string.dynamic_marker_chelsea_snippet));
marker = mapboxMap.addMarker(markerOptions);
});
FloatingActionButton fab = findViewById(R.id.fab);
fab.setColorFilter(ContextCompat.getColor(this, R.color.primary));
fab.setOnClickListener(view -> {
if (mapboxMap != null) {
updateMarker();
}
});
}
private void updateMarker() {
// update model
boolean first = (boolean) mapView.getTag();
mapView.setTag(!first);
// update marker
marker.setPosition(first ? LAT_LNG_CHELSEA : LAT_LNG_ARSENAL);
marker.setIcon(IconUtils.drawableToIcon(this, R.drawable.ic_stars, first
? ResourcesCompat.getColor(getResources(), R.color.blueAccent, getTheme()) :
ResourcesCompat.getColor(getResources(), R.color.redAccent, getTheme())
));
marker.setTitle(first
? getString(R.string.dynamic_marker_chelsea_title) : getString(R.string.dynamic_marker_arsenal_title));
marker.setSnippet(first
? getString(R.string.dynamic_marker_chelsea_snippet) : getString(R.string.dynamic_marker_arsenal_snippet));
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}

View File

@@ -0,0 +1,219 @@
package com.mapbox.mapboxsdk.testapp.activity.annotation;
import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import com.mapbox.mapboxsdk.annotations.Polygon;
import com.mapbox.mapboxsdk.annotations.PolygonOptions;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.R;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static com.mapbox.mapboxsdk.testapp.activity.annotation.PolygonActivity.Config.BLUE_COLOR;
import static com.mapbox.mapboxsdk.testapp.activity.annotation.PolygonActivity.Config.BROKEN_SHAPE_POINTS;
import static com.mapbox.mapboxsdk.testapp.activity.annotation.PolygonActivity.Config.FULL_ALPHA;
import static com.mapbox.mapboxsdk.testapp.activity.annotation.PolygonActivity.Config.NO_ALPHA;
import static com.mapbox.mapboxsdk.testapp.activity.annotation.PolygonActivity.Config.PARTIAL_ALPHA;
import static com.mapbox.mapboxsdk.testapp.activity.annotation.PolygonActivity.Config.RED_COLOR;
import static com.mapbox.mapboxsdk.testapp.activity.annotation.PolygonActivity.Config.STAR_SHAPE_HOLES;
import static com.mapbox.mapboxsdk.testapp.activity.annotation.PolygonActivity.Config.STAR_SHAPE_POINTS;
/**
* Test activity to showcase the Polygon annotation API & programmatically creating a MapView.
* <p>
* Shows how to change Polygon features as visibility, alpha, color and points.
* </p>
*/
public class PolygonActivity extends AppCompatActivity implements OnMapReadyCallback {
private MapView mapView;
private MapboxMap mapboxMap;
private Polygon polygon;
private boolean fullAlpha = true;
private boolean visible = true;
private boolean color = true;
private boolean allPoints = true;
private boolean holes = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// configure inital map state
MapboxMapOptions options = MapboxMapOptions.createFromAttributes(this, null)
.attributionTintColor(RED_COLOR)
.compassFadesWhenFacingNorth(false)
.camera(new CameraPosition.Builder()
.target(new LatLng(45.520486, -122.673541))
.zoom(12)
.tilt(40)
.build());
// create map
mapView = new MapView(this, options);
mapView.setId(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
setContentView(mapView);
}
@Override
public void onMapReady(@NonNull MapboxMap map) {
mapboxMap = map;
map.setStyle(Style.MAPBOX_STREETS);
map.setOnPolygonClickListener(polygon -> Toast.makeText(
PolygonActivity.this,
"You clicked on polygon with id = " + polygon.getId(),
Toast.LENGTH_SHORT
).show());
polygon = mapboxMap.addPolygon(new PolygonOptions()
.addAll(STAR_SHAPE_POINTS)
.fillColor(BLUE_COLOR));
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_id_alpha:
fullAlpha = !fullAlpha;
polygon.setAlpha(fullAlpha ? FULL_ALPHA : PARTIAL_ALPHA);
return true;
case R.id.action_id_visible:
visible = !visible;
polygon.setAlpha(visible ? (fullAlpha ? FULL_ALPHA : PARTIAL_ALPHA) : NO_ALPHA);
return true;
case R.id.action_id_points:
allPoints = !allPoints;
polygon.setPoints(allPoints ? STAR_SHAPE_POINTS : BROKEN_SHAPE_POINTS);
return true;
case R.id.action_id_color:
color = !color;
polygon.setFillColor(color ? BLUE_COLOR : RED_COLOR);
return true;
case R.id.action_id_holes:
holes = !holes;
polygon.setHoles(holes ? STAR_SHAPE_HOLES : Collections.<List<LatLng>>emptyList());
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_polygon, menu);
return true;
}
static final class Config {
static final int BLUE_COLOR = Color.parseColor("#3bb2d0");
static final int RED_COLOR = Color.parseColor("#AF0000");
static final float FULL_ALPHA = 1.0f;
static final float PARTIAL_ALPHA = 0.5f;
static final float NO_ALPHA = 0.0f;
static final List<LatLng> STAR_SHAPE_POINTS = new ArrayList<LatLng>() {
{
add(new LatLng(45.522585, -122.685699));
add(new LatLng(45.534611, -122.708873));
add(new LatLng(45.530883, -122.678833));
add(new LatLng(45.547115, -122.667503));
add(new LatLng(45.530643, -122.660121));
add(new LatLng(45.533529, -122.636260));
add(new LatLng(45.521743, -122.659091));
add(new LatLng(45.510677, -122.648792));
add(new LatLng(45.515008, -122.664070));
add(new LatLng(45.502496, -122.669048));
add(new LatLng(45.515369, -122.678489));
add(new LatLng(45.506346, -122.702007));
add(new LatLng(45.522585, -122.685699));
}
};
static final List<LatLng> BROKEN_SHAPE_POINTS =
STAR_SHAPE_POINTS.subList(0, STAR_SHAPE_POINTS.size() - 3);
static final List<? extends List<LatLng>> STAR_SHAPE_HOLES = new ArrayList<List<LatLng>>() {
{
add(new ArrayList<>(new ArrayList<LatLng>() {
{
add(new LatLng(45.521743, -122.669091));
add(new LatLng(45.530483, -122.676833));
add(new LatLng(45.520483, -122.676833));
add(new LatLng(45.521743, -122.669091));
}
}));
add(new ArrayList<>(new ArrayList<LatLng>() {
{
add(new LatLng(45.529743, -122.662791));
add(new LatLng(45.525543, -122.662791));
add(new LatLng(45.525543, -122.660));
add(new LatLng(45.527743, -122.660));
add(new LatLng(45.529743, -122.662791));
}
}));
}
};
}
}

View File

@@ -0,0 +1,224 @@
package com.mapbox.mapboxsdk.testapp.activity.annotation;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
import com.mapbox.mapboxsdk.annotations.Polyline;
import com.mapbox.mapboxsdk.annotations.PolylineOptions;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.testapp.R;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Test activity showcasing the Polyline annotations API.
* <p>
* Shows how to add and remove polylines.
* </p>
*/
public class PolylineActivity extends AppCompatActivity {
private static final String STATE_POLYLINE_OPTIONS = "polylineOptions";
private static final LatLng ANDORRA = new LatLng(42.505777, 1.52529);
private static final LatLng LUXEMBOURG = new LatLng(49.815273, 6.129583);
private static final LatLng MONACO = new LatLng(43.738418, 7.424616);
private static final LatLng VATICAN_CITY = new LatLng(41.902916, 12.453389);
private static final LatLng SAN_MARINO = new LatLng(43.942360, 12.457777);
private static final LatLng LIECHTENSTEIN = new LatLng(47.166000, 9.555373);
private static final float FULL_ALPHA = 1.0f;
private static final float PARTIAL_ALPHA = 0.5f;
private static final float NO_ALPHA = 0.0f;
private List<Polyline> polylines;
private ArrayList<PolylineOptions> polylineOptions = new ArrayList<>();
private MapView mapView;
private MapboxMap mapboxMap;
private boolean fullAlpha = true;
private boolean visible = true;
private boolean width = true;
private boolean color = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_polyline);
if (savedInstanceState != null) {
polylineOptions = savedInstanceState.getParcelableArrayList(STATE_POLYLINE_OPTIONS);
} else {
polylineOptions.addAll(getAllPolylines());
}
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(mapboxMap -> {
PolylineActivity.this.mapboxMap = mapboxMap;
mapboxMap.setStyle(Style.SATELLITE_STREETS);
mapboxMap.setOnPolylineClickListener(polyline -> Toast.makeText(
PolylineActivity.this,
"You clicked on polyline with id = " + polyline.getId(),
Toast.LENGTH_SHORT
).show());
polylines = mapboxMap.addPolylines(polylineOptions);
});
View fab = findViewById(R.id.fab);
if (fab != null) {
fab.setOnClickListener(view -> {
if (mapboxMap != null) {
if (polylines != null && polylines.size() > 0) {
if (polylines.size() == 1) {
// test for removing annotation
mapboxMap.removeAnnotation(polylines.get(0));
} else {
// test for removing annotations
mapboxMap.removeAnnotations(polylines);
}
}
polylineOptions.clear();
polylineOptions.addAll(getRandomLine());
polylines = mapboxMap.addPolylines(polylineOptions);
}
});
}
}
private List<PolylineOptions> getAllPolylines() {
List<PolylineOptions> options = new ArrayList<>();
options.add(generatePolyline(ANDORRA, LUXEMBOURG, "#F44336"));
options.add(generatePolyline(ANDORRA, MONACO, "#FF5722"));
options.add(generatePolyline(MONACO, VATICAN_CITY, "#673AB7"));
options.add(generatePolyline(VATICAN_CITY, SAN_MARINO, "#009688"));
options.add(generatePolyline(SAN_MARINO, LIECHTENSTEIN, "#795548"));
options.add(generatePolyline(LIECHTENSTEIN, LUXEMBOURG, "#3F51B5"));
return options;
}
private PolylineOptions generatePolyline(LatLng start, LatLng end, String color) {
PolylineOptions line = new PolylineOptions();
line.add(start);
line.add(end);
line.color(Color.parseColor(color));
return line;
}
public List<PolylineOptions> getRandomLine() {
final List<PolylineOptions> randomLines = getAllPolylines();
Collections.shuffle(randomLines);
return new ArrayList<PolylineOptions>() {
{
add(randomLines.get(0));
}
};
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
outState.putParcelableArrayList(STATE_POLYLINE_OPTIONS, polylineOptions);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_polyline, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (polylines.size() <= 0) {
Toast.makeText(PolylineActivity.this, "No polylines on map", Toast.LENGTH_LONG).show();
return super.onOptionsItemSelected(item);
}
switch (item.getItemId()) {
case R.id.action_id_remove:
// test to remove all annotations
polylineOptions.clear();
mapboxMap.clear();
polylines.clear();
return true;
case R.id.action_id_alpha:
fullAlpha = !fullAlpha;
for (Polyline p : polylines) {
p.setAlpha(fullAlpha ? FULL_ALPHA : PARTIAL_ALPHA);
}
return true;
case R.id.action_id_color:
color = !color;
for (Polyline p : polylines) {
p.setColor(color ? Color.RED : Color.BLUE);
}
return true;
case R.id.action_id_width:
width = !width;
for (Polyline p : polylines) {
p.setWidth(width ? 3.0f : 5.0f);
}
return true;
case R.id.action_id_visible:
visible = !visible;
for (Polyline p : polylines) {
p.setAlpha(visible ? (fullAlpha ? FULL_ALPHA : PARTIAL_ALPHA) : NO_ALPHA);
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}

View File

@@ -0,0 +1,152 @@
package com.mapbox.mapboxsdk.testapp.activity.annotation;
import android.graphics.PointF;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
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.Style;
import com.mapbox.mapboxsdk.testapp.R;
import java.text.DecimalFormat;
import java.util.ArrayList;
/**
* Test activity showcasing to add a Marker on click.
* <p>
* Shows how to use a OnMapClickListener and a OnMapLongClickListener
* </p>
*/
public class PressForMarkerActivity extends AppCompatActivity {
private MapView mapView;
private MapboxMap mapboxMap;
private ArrayList<MarkerOptions> markerList = new ArrayList<>();
private static final DecimalFormat LAT_LON_FORMATTER = new DecimalFormat("#.#####");
private static String STATE_MARKER_LIST = "markerList";
@Override
protected void onCreate(@Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_press_for_marker);
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(map -> {
mapboxMap = map;
resetMap();
mapboxMap.addOnMapLongClickListener(point -> {
addMarker(point);
return false;
});
mapboxMap.addOnMapClickListener(point -> {
addMarker(point);
return false;
});
mapboxMap.setStyle(Style.MAPBOX_STREETS);
if (savedInstanceState != null) {
markerList = savedInstanceState.getParcelableArrayList(STATE_MARKER_LIST);
if (markerList != null) {
mapboxMap.addMarkers(markerList);
}
}
});
}
private void addMarker(LatLng point) {
final PointF pixel = mapboxMap.getProjection().toScreenLocation(point);
String title = LAT_LON_FORMATTER.format(point.getLatitude()) + ", "
+ LAT_LON_FORMATTER.format(point.getLongitude());
String snippet = "X = " + (int) pixel.x + ", Y = " + (int) pixel.y;
MarkerOptions marker = new MarkerOptions()
.position(point)
.title(title)
.snippet(snippet);
markerList.add(marker);
mapboxMap.addMarker(marker);
}
private void resetMap() {
if (mapboxMap == null) {
return;
}
markerList.clear();
mapboxMap.removeAnnotations();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_press_for_marker, menu);
return true;
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
outState.putParcelableArrayList(STATE_MARKER_LIST, markerList);
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menuItemReset:
resetMap();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}

View File

@@ -0,0 +1,173 @@
package com.mapbox.mapboxsdk.testapp.activity.camera;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;
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.testapp.R;
import timber.log.Timber;
/**
* Test activity showcasing the Camera API and listen to camera updates by animating the camera above London.
* <p>
* Shows how to use animate, ease and move camera update factory methods.
* </p>
*/
public class CameraAnimationTypeActivity extends AppCompatActivity implements OnMapReadyCallback {
private static final LatLng LAT_LNG_LONDON_EYE = new LatLng(51.50325, -0.11968);
private static final LatLng LAT_LNG_TOWER_BRIDGE = new LatLng(51.50550, -0.07520);
private final MapboxMap.CancelableCallback callback = new MapboxMap.CancelableCallback() {
@Override
public void onCancel() {
Timber.i("Duration onCancel Callback called.");
Toast.makeText(
CameraAnimationTypeActivity.this.getApplicationContext(),
"Ease onCancel Callback called.",
Toast.LENGTH_LONG).show();
}
@Override
public void onFinish() {
Timber.i("Duration onFinish Callback called.");
Toast.makeText(
CameraAnimationTypeActivity.this.getApplicationContext(),
"Ease onFinish Callback called.",
Toast.LENGTH_LONG).show();
}
};
private MapboxMap mapboxMap;
private MapView mapView;
private boolean cameraState;
private MapboxMap.OnCameraIdleListener cameraIdleListener = new MapboxMap.OnCameraIdleListener() {
@Override
public void onCameraIdle() {
if (mapboxMap != null) {
Timber.w(mapboxMap.getCameraPosition().toString());
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera_animation_types);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
}
@Override
public void onMapReady(@NonNull MapboxMap map) {
mapboxMap = map;
mapboxMap.setStyle(new Style.Builder().fromUri(Style.MAPBOX_STREETS));
mapboxMap.getUiSettings().setAttributionEnabled(false);
mapboxMap.getUiSettings().setLogoEnabled(false);
mapboxMap.addOnCameraIdleListener(cameraIdleListener);
// handle move button clicks
View moveButton = findViewById(R.id.cameraMoveButton);
if (moveButton != null) {
moveButton.setOnClickListener(view -> {
CameraPosition cameraPosition = new CameraPosition.Builder()
.target(getNextLatLng())
.zoom(14)
.tilt(30)
.tilt(0)
.build();
mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
});
}
// handle ease button clicks
View easeButton = findViewById(R.id.cameraEaseButton);
if (easeButton != null) {
easeButton.setOnClickListener(view -> {
CameraPosition cameraPosition = new CameraPosition.Builder()
.target(getNextLatLng())
.zoom(15)
.bearing(180)
.tilt(30)
.build();
mapboxMap.easeCamera(CameraUpdateFactory.newCameraPosition(cameraPosition), 7500, callback);
});
}
// handle animate button clicks
View animateButton = findViewById(R.id.cameraAnimateButton);
if (animateButton != null) {
animateButton.setOnClickListener(view -> {
CameraPosition cameraPosition = new CameraPosition.Builder()
.target(getNextLatLng())
.bearing(270)
.tilt(20)
.build();
mapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition), 7500, callback);
});
}
}
private LatLng getNextLatLng() {
cameraState = !cameraState;
return cameraState ? LAT_LNG_TOWER_BRIDGE : LAT_LNG_LONDON_EYE;
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mapboxMap != null) {
mapboxMap.removeOnCameraIdleListener(cameraIdleListener);
}
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}

View File

@@ -0,0 +1,281 @@
package com.mapbox.mapboxsdk.testapp.activity.camera;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.util.LongSparseArray;
import android.support.v4.view.animation.FastOutLinearInInterpolator;
import android.support.v4.view.animation.FastOutSlowInInterpolator;
import android.support.v4.view.animation.PathInterpolatorCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.animation.AnticipateOvershootInterpolator;
import android.view.animation.BounceInterpolator;
import android.view.animation.Interpolator;
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.testapp.R;
/**
* Test activity showcasing using Android SDK animators to animate camera position changes.
*/
public class CameraAnimatorActivity extends AppCompatActivity implements OnMapReadyCallback {
private static final double ANIMATION_DELAY_FACTOR = 1.5;
private static final LatLng START_LAT_LNG = new LatLng(37.787947, -122.407432);
private final LongSparseArray<Animator> animators = new LongSparseArray<>();
private Animator set;
{
AnimatorSet accelerateDecelerateAnimatorSet = new AnimatorSet();
accelerateDecelerateAnimatorSet.playTogether(
createLatLngAnimator(START_LAT_LNG, new LatLng(37.826715, -122.422795)),
obtainExampleInterpolator(new FastOutSlowInInterpolator(), 2500)
);
animators.put(R.id.menu_action_accelerate_decelerate_interpolator, accelerateDecelerateAnimatorSet);
AnimatorSet bounceAnimatorSet = new AnimatorSet();
bounceAnimatorSet.playTogether(
createLatLngAnimator(START_LAT_LNG, new LatLng(37.787947, -122.407432)),
obtainExampleInterpolator(new BounceInterpolator(), 3750)
);
animators.put(R.id.menu_action_bounce_interpolator, bounceAnimatorSet);
animators.put(R.id.menu_action_anticipate_overshoot_interpolator,
obtainExampleInterpolator(new AnticipateOvershootInterpolator(), 2500)
);
animators.put(R.id.menu_action_path_interpolator, obtainExampleInterpolator(
PathInterpolatorCompat.create(.22f, .68f, 0, 1.71f), 2500));
}
private MapView mapView;
private MapboxMap mapboxMap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera_animator);
mapView = (MapView) findViewById(R.id.mapView);
if (mapView != null) {
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
}
}
@Override
public void onMapReady(@NonNull final MapboxMap map) {
mapboxMap = map;
map.setStyle(Style.MAPBOX_STREETS);
initFab();
}
private void initFab() {
findViewById(R.id.fab).setOnClickListener(view -> {
view.setVisibility(View.GONE);
CameraPosition animatedPosition = new CameraPosition.Builder()
.target(new LatLng(37.789992, -122.402214))
.tilt(60)
.zoom(14.5f)
.bearing(135)
.build();
set = createExampleAnimator(mapboxMap.getCameraPosition(), animatedPosition);
set.start();
});
}
//
// Animator API used for the animation on the FAB
//
private Animator createExampleAnimator(CameraPosition currentPosition, CameraPosition targetPosition) {
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(createLatLngAnimator(currentPosition.target, targetPosition.target));
animatorSet.play(createZoomAnimator(currentPosition.zoom, targetPosition.zoom));
animatorSet.play(createBearingAnimator(currentPosition.bearing, targetPosition.bearing));
animatorSet.play(createTiltAnimator(currentPosition.tilt, targetPosition.tilt));
return animatorSet;
}
private Animator createLatLngAnimator(LatLng currentPosition, LatLng targetPosition) {
ValueAnimator latLngAnimator = ValueAnimator.ofObject(new LatLngEvaluator(), currentPosition, targetPosition);
latLngAnimator.setDuration((long) (1000 * ANIMATION_DELAY_FACTOR));
latLngAnimator.setInterpolator(new FastOutSlowInInterpolator());
latLngAnimator.addUpdateListener(animation -> mapboxMap.moveCamera(
CameraUpdateFactory.newLatLng((LatLng) animation.getAnimatedValue()))
);
return latLngAnimator;
}
private Animator createZoomAnimator(double currentZoom, double targetZoom) {
ValueAnimator zoomAnimator = ValueAnimator.ofFloat((float) currentZoom, (float) targetZoom);
zoomAnimator.setDuration((long) (2200 * ANIMATION_DELAY_FACTOR));
zoomAnimator.setStartDelay((long) (600 * ANIMATION_DELAY_FACTOR));
zoomAnimator.setInterpolator(new AnticipateOvershootInterpolator());
zoomAnimator.addUpdateListener(animation -> mapboxMap.moveCamera(
CameraUpdateFactory.zoomTo((Float) animation.getAnimatedValue()))
);
return zoomAnimator;
}
private Animator createBearingAnimator(double currentBearing, double targetBearing) {
ValueAnimator bearingAnimator = ValueAnimator.ofFloat((float) currentBearing, (float) targetBearing);
bearingAnimator.setDuration((long) (1000 * ANIMATION_DELAY_FACTOR));
bearingAnimator.setStartDelay((long) (1000 * ANIMATION_DELAY_FACTOR));
bearingAnimator.setInterpolator(new FastOutLinearInInterpolator());
bearingAnimator.addUpdateListener(animation -> mapboxMap.moveCamera(
CameraUpdateFactory.bearingTo((Float) animation.getAnimatedValue()))
);
return bearingAnimator;
}
private Animator createTiltAnimator(double currentTilt, double targetTilt) {
ValueAnimator tiltAnimator = ValueAnimator.ofFloat((float) currentTilt, (float) targetTilt);
tiltAnimator.setDuration((long) (1000 * ANIMATION_DELAY_FACTOR));
tiltAnimator.setStartDelay((long) (1500 * ANIMATION_DELAY_FACTOR));
tiltAnimator.addUpdateListener(animation -> mapboxMap.moveCamera(
CameraUpdateFactory.tiltTo((Float) animation.getAnimatedValue()))
);
return tiltAnimator;
}
//
// Interpolator examples
//
private Animator obtainExampleInterpolator(int menuItemId) {
return animators.get(menuItemId);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_animator, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (mapboxMap == null) {
return false;
}
if (item.getItemId() != android.R.id.home) {
findViewById(R.id.fab).setVisibility(View.GONE);
resetCameraPosition();
playAnimation(item.getItemId());
}
return super.onOptionsItemSelected(item);
}
private void resetCameraPosition() {
mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(
new CameraPosition.Builder()
.target(START_LAT_LNG)
.zoom(11)
.bearing(0)
.tilt(0)
.build()
));
}
private void playAnimation(int itemId) {
Animator animator = obtainExampleInterpolator(itemId);
if (animator != null) {
animator.cancel();
animator.start();
}
}
private Animator obtainExampleInterpolator(Interpolator interpolator, long duration) {
ValueAnimator zoomAnimator = ValueAnimator.ofFloat(11.0f, 16.0f);
zoomAnimator.setDuration((long) (duration * ANIMATION_DELAY_FACTOR));
zoomAnimator.setInterpolator(interpolator);
zoomAnimator.addUpdateListener(animation -> mapboxMap.moveCamera(
CameraUpdateFactory.zoomTo((Float) animation.getAnimatedValue()))
);
return zoomAnimator;
}
//
// MapView lifecycle
//
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
for (int i = 0; i < animators.size(); i++) {
animators.get(animators.keyAt(i)).cancel();
}
if (set != null) {
set.cancel();
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
/**
* Helper class to evaluate LatLng objects with a ValueAnimator
*/
private static class LatLngEvaluator implements TypeEvaluator<LatLng> {
private final LatLng latLng = new LatLng();
@Override
public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) {
latLng.setLatitude(startValue.getLatitude()
+ ((endValue.getLatitude() - startValue.getLatitude()) * fraction));
latLng.setLongitude(startValue.getLongitude()
+ ((endValue.getLongitude() - startValue.getLongitude()) * fraction));
return latLng;
}
}
}

View File

@@ -0,0 +1,279 @@
package com.mapbox.mapboxsdk.testapp.activity.camera;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.app.FragmentActivity;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.Toolbar;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
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.testapp.R;
import timber.log.Timber;
import static com.mapbox.mapboxsdk.constants.GeometryConstants.MAX_LATITUDE;
import static com.mapbox.mapboxsdk.constants.GeometryConstants.MIN_LATITUDE;
/**
* Test activity showcasing how to listen to camera change events.
*/
public class CameraPositionActivity extends FragmentActivity implements OnMapReadyCallback, View.OnClickListener,
MapboxMap.OnMapLongClickListener {
private MapView mapView;
private MapboxMap mapboxMap;
private FloatingActionButton fab;
private boolean logCameraChanges;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera_position);
Toolbar toolbar = findViewById(R.id.toolbar);
toolbar.setTitle(R.string.activity_camera_position);
toolbar.setNavigationIcon(R.drawable.ic_ab_back);
toolbar.setNavigationOnClickListener(v -> finish());
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
}
@Override
public void onMapReady(@NonNull final MapboxMap map) {
mapboxMap = map;
map.setStyle(Style.SATELLITE_STREETS, style -> {
// add a listener to FAB
fab = findViewById(R.id.fab);
fab.setColorFilter(ContextCompat.getColor(CameraPositionActivity.this, R.color.primary));
fab.setOnClickListener(this);
toggleLogCameraChanges();
// listen to long click events to toggle logging camera changes
mapboxMap.addOnMapLongClickListener(this);
});
}
@Override
public boolean onMapLongClick(@NonNull LatLng point) {
toggleLogCameraChanges();
return false;
}
@Override
public void onClick(View view) {
Context context = view.getContext();
final View dialogContent = LayoutInflater.from(context).inflate(R.layout.dialog_camera_position, null);
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(R.string.dialog_camera_position);
builder.setView(onInflateDialogContent(dialogContent));
builder.setPositiveButton("Animate", new DialogClickListener(mapboxMap, dialogContent));
builder.setNegativeButton("Cancel", null);
builder.setCancelable(false);
builder.show();
}
private void toggleLogCameraChanges() {
logCameraChanges = !logCameraChanges;
if (logCameraChanges) {
mapboxMap.addOnCameraIdleListener(idleListener);
mapboxMap.addOnCameraMoveCancelListener(moveCanceledListener);
mapboxMap.addOnCameraMoveListener(moveListener);
mapboxMap.addOnCameraMoveStartedListener(moveStartedListener);
} else {
mapboxMap.removeOnCameraIdleListener(idleListener);
mapboxMap.removeOnCameraMoveCancelListener(moveCanceledListener);
mapboxMap.removeOnCameraMoveListener(moveListener);
mapboxMap.removeOnCameraMoveStartedListener(moveStartedListener);
}
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mapboxMap != null) {
mapboxMap.removeOnMapLongClickListener(this);
}
mapView.onDestroy();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
private View onInflateDialogContent(View view) {
linkTextView(view, R.id.value_lat, R.id.seekbar_lat, new LatLngChangeListener(), 180 + 38);
linkTextView(view, R.id.value_lon, R.id.seekbar_lon, new LatLngChangeListener(), 180 - 77);
linkTextView(view, R.id.value_zoom, R.id.seekbar_zoom, new ValueChangeListener(), 6);
linkTextView(view, R.id.value_bearing, R.id.seekbar_bearing, new ValueChangeListener(), 90);
linkTextView(view, R.id.value_tilt, R.id.seekbar_tilt, new ValueChangeListener(), 40);
return view;
}
private void linkTextView(
View view, @IdRes int textViewRes, @IdRes int seekBarRes, ValueChangeListener listener, int defaultValue) {
final TextView value = (TextView) view.findViewById(textViewRes);
SeekBar seekBar = (SeekBar) view.findViewById(seekBarRes);
listener.setLinkedValueView(value);
seekBar.setOnSeekBarChangeListener(listener);
seekBar.setProgress(defaultValue);
}
private MapboxMap.OnCameraIdleListener idleListener = new MapboxMap.OnCameraIdleListener() {
@Override
public void onCameraIdle() {
Timber.e("OnCameraIdle");
fab.setColorFilter(ContextCompat.getColor(CameraPositionActivity.this, android.R.color.holo_green_dark));
}
};
private MapboxMap.OnCameraMoveListener moveListener = new MapboxMap.OnCameraMoveListener() {
@Override
public void onCameraMove() {
Timber.e("OnCameraMove");
fab.setColorFilter(ContextCompat.getColor(CameraPositionActivity.this, android.R.color.holo_orange_dark));
}
};
private MapboxMap.OnCameraMoveCanceledListener moveCanceledListener = () -> Timber.e("OnCameraMoveCanceled");
private MapboxMap.OnCameraMoveStartedListener moveStartedListener = new MapboxMap.OnCameraMoveStartedListener() {
private final String[] REASONS = {"REASON_API_GESTURE", "REASON_DEVELOPER_ANIMATION", "REASON_API_ANIMATION"};
@Override
public void onCameraMoveStarted(int reason) {
// reason ranges from 1 <-> 3
fab.setColorFilter(ContextCompat.getColor(CameraPositionActivity.this, android.R.color.holo_red_dark));
Timber.e("OnCameraMoveStarted: %s", REASONS[reason - 1]);
}
};
private class ValueChangeListener implements SeekBar.OnSeekBarChangeListener {
protected TextView textView;
public void setLinkedValueView(TextView textView) {
this.textView = textView;
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
textView.setText(String.valueOf(progress));
}
}
private class LatLngChangeListener extends ValueChangeListener {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
super.onProgressChanged(seekBar, progress - 180, fromUser);
}
}
private static class DialogClickListener implements DialogInterface.OnClickListener {
private MapboxMap mapboxMap;
private View dialogContent;
public DialogClickListener(MapboxMap mapboxMap, View view) {
this.mapboxMap = mapboxMap;
this.dialogContent = view;
}
@Override
public void onClick(DialogInterface dialog, int which) {
double latitude = Double.parseDouble(
((TextView) dialogContent.findViewById(R.id.value_lat)).getText().toString());
double longitude = Double.parseDouble(
((TextView) dialogContent.findViewById(R.id.value_lon)).getText().toString());
double zoom = Double.parseDouble(
((TextView) dialogContent.findViewById(R.id.value_zoom)).getText().toString());
double bearing = Double.parseDouble(
((TextView) dialogContent.findViewById(R.id.value_bearing)).getText().toString());
double tilt = Double.parseDouble(
((TextView) dialogContent.findViewById(R.id.value_tilt)).getText().toString());
if (latitude < MIN_LATITUDE || latitude > MAX_LATITUDE) {
Toast.makeText(dialogContent.getContext(), "latitude value must be set "
+ " between " + MIN_LATITUDE + " and " + MAX_LATITUDE,
Toast.LENGTH_SHORT).show();
return;
}
CameraPosition cameraPosition = new CameraPosition.Builder()
.target(new LatLng(latitude, longitude))
.zoom(zoom)
.bearing(bearing)
.tilt(tilt)
.build();
mapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition), 5000,
new MapboxMap.CancelableCallback() {
@Override
public void onCancel() {
Timber.v("OnCancel called");
}
@Override
public void onFinish() {
Timber.v("OnFinish called");
}
});
Timber.v(cameraPosition.toString());
}
}
}

View File

@@ -0,0 +1,456 @@
package com.mapbox.mapboxsdk.testapp.activity.camera;
import android.graphics.Typeface;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.ColorInt;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.mapbox.android.gestures.AndroidGesturesManager;
import com.mapbox.android.gestures.MoveGestureDetector;
import com.mapbox.android.gestures.RotateGestureDetector;
import com.mapbox.android.gestures.ShoveGestureDetector;
import com.mapbox.android.gestures.StandardScaleGestureDetector;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
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.Style;
import com.mapbox.mapboxsdk.maps.UiSettings;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.utils.FontCache;
import com.mapbox.mapboxsdk.testapp.utils.ResourceUtils;
import java.lang.annotation.Retention;
import java.util.ArrayList;
import java.util.List;
import static java.lang.annotation.RetentionPolicy.SOURCE;
/**
* Test activity showcasing APIs around gestures implementation.
*/
public class GestureDetectorActivity extends AppCompatActivity {
private static final int MAX_NUMBER_OF_ALERTS = 30;
private MapView mapView;
private MapboxMap mapboxMap;
private RecyclerView recyclerView;
private GestureAlertsAdapter gestureAlertsAdapter;
private AndroidGesturesManager gesturesManager;
@Nullable
private Marker marker;
@Nullable
private LatLng focalPointLatLng;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gesture_detector);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(mapboxMap -> {
GestureDetectorActivity.this.mapboxMap = mapboxMap;
mapboxMap.setStyle(Style.MAPBOX_STREETS);
initializeMap();
});
recyclerView = findViewById(R.id.alerts_recycler);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
gestureAlertsAdapter = new GestureAlertsAdapter();
recyclerView.setAdapter(gestureAlertsAdapter);
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
gestureAlertsAdapter.cancelUpdates();
mapView.onPause();
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
private void initializeMap() {
gesturesManager = mapboxMap.getGesturesManager();
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) recyclerView.getLayoutParams();
layoutParams.height = (int) (mapView.getHeight() / 1.75);
layoutParams.width = (mapView.getWidth() / 3);
recyclerView.setLayoutParams(layoutParams);
attachListeners();
fixedFocalPointEnabled(mapboxMap.getUiSettings().getFocalPoint() != null);
}
public void attachListeners() {
mapboxMap.addOnMoveListener(new MapboxMap.OnMoveListener() {
@Override
public void onMoveBegin(@NonNull MoveGestureDetector detector) {
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_START, "MOVE START"));
}
@Override
public void onMove(@NonNull MoveGestureDetector detector) {
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_PROGRESS, "MOVE PROGRESS"));
}
@Override
public void onMoveEnd(@NonNull MoveGestureDetector detector) {
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_END, "MOVE END"));
recalculateFocalPoint();
}
});
mapboxMap.addOnRotateListener(new MapboxMap.OnRotateListener() {
@Override
public void onRotateBegin(@NonNull RotateGestureDetector detector) {
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_START, "ROTATE START"));
}
@Override
public void onRotate(@NonNull RotateGestureDetector detector) {
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_PROGRESS, "ROTATE PROGRESS"));
recalculateFocalPoint();
}
@Override
public void onRotateEnd(@NonNull RotateGestureDetector detector) {
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_END, "ROTATE END"));
}
});
mapboxMap.addOnScaleListener(new MapboxMap.OnScaleListener() {
@Override
public void onScaleBegin(@NonNull StandardScaleGestureDetector detector) {
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_START, "SCALE START"));
if (focalPointLatLng != null) {
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_OTHER, "INCREASING MOVE THRESHOLD"));
gesturesManager.getMoveGestureDetector().setMoveThreshold(
ResourceUtils.convertDpToPx(GestureDetectorActivity.this, 175));
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_OTHER, "MANUALLY INTERRUPTING MOVE"));
gesturesManager.getMoveGestureDetector().interrupt();
}
recalculateFocalPoint();
}
@Override
public void onScale(@NonNull StandardScaleGestureDetector detector) {
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_PROGRESS, "SCALE PROGRESS"));
}
@Override
public void onScaleEnd(@NonNull StandardScaleGestureDetector detector) {
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_END, "SCALE END"));
if (focalPointLatLng != null) {
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_OTHER, "REVERTING MOVE THRESHOLD"));
gesturesManager.getMoveGestureDetector().setMoveThreshold(0f);
}
}
});
mapboxMap.addOnShoveListener(new MapboxMap.OnShoveListener() {
@Override
public void onShoveBegin(@NonNull ShoveGestureDetector detector) {
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_START, "SHOVE START"));
}
@Override
public void onShove(@NonNull ShoveGestureDetector detector) {
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_PROGRESS, "SHOVE PROGRESS"));
}
@Override
public void onShoveEnd(@NonNull ShoveGestureDetector detector) {
gestureAlertsAdapter.addAlert(new GestureAlert(GestureAlert.TYPE_END, "SHOVE END"));
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_gestures, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
UiSettings uiSettings = mapboxMap.getUiSettings();
switch (item.getItemId()) {
case R.id.menu_gesture_focus_point:
fixedFocalPointEnabled(focalPointLatLng == null);
return true;
case R.id.menu_gesture_animation:
uiSettings.setScaleVelocityAnimationEnabled(!uiSettings.isScaleVelocityAnimationEnabled());
uiSettings.setRotateVelocityAnimationEnabled(!uiSettings.isRotateVelocityAnimationEnabled());
uiSettings.setFlingVelocityAnimationEnabled(!uiSettings.isFlingVelocityAnimationEnabled());
return true;
case R.id.menu_gesture_rotate:
uiSettings.setRotateGesturesEnabled(!uiSettings.isRotateGesturesEnabled());
return true;
case R.id.menu_gesture_tilt:
uiSettings.setTiltGesturesEnabled(!uiSettings.isTiltGesturesEnabled());
return true;
case R.id.menu_gesture_zoom:
uiSettings.setZoomGesturesEnabled(!uiSettings.isZoomGesturesEnabled());
return true;
case R.id.menu_gesture_scroll:
uiSettings.setScrollGesturesEnabled(!uiSettings.isScrollGesturesEnabled());
return true;
case R.id.menu_gesture_double_tap:
uiSettings.setDoubleTapGesturesEnabled(!uiSettings.isDoubleTapGesturesEnabled());
return true;
case R.id.menu_gesture_quick_zoom:
uiSettings.setQuickZoomGesturesEnabled(!uiSettings.isQuickZoomGesturesEnabled());
return true;
}
return super.onOptionsItemSelected(item);
}
private void fixedFocalPointEnabled(boolean enabled) {
if (enabled) {
focalPointLatLng = new LatLng(51.50325, -0.12968);
marker = mapboxMap.addMarker(new MarkerOptions().position(focalPointLatLng));
mapboxMap.easeCamera(CameraUpdateFactory.newLatLngZoom(focalPointLatLng, 16),
new MapboxMap.CancelableCallback() {
@Override
public void onCancel() {
recalculateFocalPoint();
}
@Override
public void onFinish() {
recalculateFocalPoint();
}
});
} else {
if (marker != null) {
mapboxMap.removeMarker(marker);
marker = null;
}
focalPointLatLng = null;
mapboxMap.getUiSettings().setFocalPoint(null);
}
}
private void recalculateFocalPoint() {
if (focalPointLatLng != null) {
mapboxMap.getUiSettings().setFocalPoint(
mapboxMap.getProjection().toScreenLocation(focalPointLatLng)
);
}
}
private static class GestureAlertsAdapter extends RecyclerView.Adapter<GestureAlertsAdapter.ViewHolder> {
private boolean isUpdating;
private final Handler updateHandler = new Handler();
private final List<GestureAlert> alerts = new ArrayList<>();
public static class ViewHolder extends RecyclerView.ViewHolder {
TextView alertMessageTv;
@ColorInt
public int textColor;
ViewHolder(View view) {
super(view);
Typeface typeface = FontCache.get("Roboto-Regular.ttf", view.getContext());
alertMessageTv = view.findViewById(R.id.alert_message);
alertMessageTv.setTypeface(typeface);
}
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_gesture_alert, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
GestureAlert alert = alerts.get(position);
holder.alertMessageTv.setText(alert.getMessage());
holder.alertMessageTv.setTextColor(
ContextCompat.getColor(holder.alertMessageTv.getContext(), alert.getColor()));
}
@Override
public int getItemCount() {
return alerts.size();
}
void addAlert(GestureAlert alert) {
for (GestureAlert gestureAlert : alerts) {
if (gestureAlert.getAlertType() != GestureAlert.TYPE_PROGRESS) {
break;
}
if (alert.getAlertType() == GestureAlert.TYPE_PROGRESS && gestureAlert.equals(alert)) {
return;
}
}
if (getItemCount() >= MAX_NUMBER_OF_ALERTS) {
alerts.remove(getItemCount() - 1);
}
alerts.add(0, alert);
if (!isUpdating) {
isUpdating = true;
updateHandler.postDelayed(updateRunnable, 250);
}
}
private Runnable updateRunnable = new Runnable() {
@Override
public void run() {
notifyDataSetChanged();
isUpdating = false;
}
};
void cancelUpdates() {
updateHandler.removeCallbacksAndMessages(null);
}
}
private static class GestureAlert {
@Retention(SOURCE)
@IntDef( {TYPE_NONE, TYPE_START, TYPE_PROGRESS, TYPE_END, TYPE_OTHER})
@interface Type {
}
static final int TYPE_NONE = 0;
static final int TYPE_START = 1;
static final int TYPE_END = 2;
static final int TYPE_PROGRESS = 3;
static final int TYPE_OTHER = 4;
@Type
private int alertType;
private String message;
@ColorInt
private int color;
GestureAlert(@Type int alertType, String message) {
this.alertType = alertType;
this.message = message;
switch (alertType) {
case TYPE_NONE:
color = android.R.color.black;
break;
case TYPE_END:
color = android.R.color.holo_red_dark;
break;
case TYPE_OTHER:
color = android.R.color.holo_purple;
break;
case TYPE_PROGRESS:
color = android.R.color.holo_orange_dark;
break;
case TYPE_START:
color = android.R.color.holo_green_dark;
break;
}
}
int getAlertType() {
return alertType;
}
String getMessage() {
return message;
}
int getColor() {
return color;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
GestureAlert that = (GestureAlert) o;
if (alertType != that.alertType) {
return false;
}
return message != null ? message.equals(that.message) : that.message == null;
}
@Override
public int hashCode() {
int result = alertType;
result = 31 * result + (message != null ? message.hashCode() : 0);
return result;
}
}
}

View File

@@ -0,0 +1,165 @@
package com.mapbox.mapboxsdk.testapp.activity.camera
import android.content.Context
import android.os.Bundle
import android.support.design.widget.BottomSheetBehavior
import android.support.v7.app.AppCompatActivity
import android.view.View
import com.mapbox.geojson.FeatureCollection
import com.mapbox.geojson.FeatureCollection.fromJson
import com.mapbox.geojson.Point
import com.mapbox.mapboxsdk.geometry.LatLng
import com.mapbox.mapboxsdk.geometry.LatLngBounds
import com.mapbox.mapboxsdk.maps.MapboxMap
import com.mapbox.mapboxsdk.maps.Style
import com.mapbox.mapboxsdk.style.layers.Property.ICON_ANCHOR_CENTER
import com.mapbox.mapboxsdk.style.layers.PropertyFactory.*
import com.mapbox.mapboxsdk.style.layers.SymbolLayer
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource
import com.mapbox.mapboxsdk.testapp.R
import com.mapbox.mapboxsdk.testapp.utils.GeoParseUtil.loadStringFromAssets
import com.mapbox.mapboxsdk.utils.BitmapUtils
import java.net.URISyntaxException
import kotlinx.android.synthetic.main.activity_latlngbounds.*
/**
* Test activity showcasing using the LatLngBounds camera API.
*/
class LatLngBoundsActivity : AppCompatActivity() {
private lateinit var mapboxMap: MapboxMap
private lateinit var bottomSheetBehavior: BottomSheetBehavior<*>
private lateinit var bounds: LatLngBounds
private val peekHeight by lazy {
375.toPx(this) // 375dp
}
private val additionalPadding by lazy {
32.toPx(this) // 32dp
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_latlngbounds)
initMapView(savedInstanceState)
}
private fun initMapView(savedInstanceState: Bundle?) {
mapView.onCreate(savedInstanceState)
mapView.getMapAsync { map ->
mapboxMap = map
val featureCollection: FeatureCollection = fromJson(loadStringFromAssets(this, "points-sf.geojson"))
bounds = createBounds(featureCollection)
map.getCameraForLatLngBounds(bounds, createPadding(peekHeight))?.let {
map.cameraPosition = it
}
try {
loadStyle(featureCollection)
} catch (e: URISyntaxException) {
e.printStackTrace()
}
}
}
private fun loadStyle(featureCollection: FeatureCollection) {
mapboxMap.setStyle(Style.Builder()
.fromUri(Style.MAPBOX_STREETS)
.withLayer(SymbolLayer("symbol", "symbol")
.withProperties(
iconAllowOverlap(true),
iconIgnorePlacement(true),
iconImage("icon"),
iconAnchor(ICON_ANCHOR_CENTER)
)
)
.withSource(GeoJsonSource("symbol", featureCollection))
.withImage("icon", BitmapUtils.getDrawableFromRes(this@LatLngBoundsActivity, R.drawable.ic_android)!!)
) {
initBottomSheet()
fab.setOnClickListener { bottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED }
}
}
private fun initBottomSheet() {
bottomSheetBehavior = BottomSheetBehavior.from(bottomSheet)
bottomSheetBehavior.setBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
override fun onSlide(bottomSheet: View, slideOffset: Float) {
val offset = convertSlideOffset(slideOffset)
val bottomPadding = (peekHeight * offset).toInt()
mapboxMap.getCameraForLatLngBounds(bounds, createPadding(bottomPadding))?.let {
mapboxMap.cameraPosition = it
}
}
override fun onStateChanged(bottomSheet: View, newState: Int) {
// no-op
}
})
}
// slideOffset ranges from NaN to -1.0, range from 1.0 to 0 instead
fun convertSlideOffset(slideOffset: Float): Float {
return if (slideOffset.equals(Float.NaN)) {
1.0f
} else {
1 + slideOffset
}
}
fun createPadding(bottomPadding: Int): IntArray {
return intArrayOf(additionalPadding, additionalPadding, additionalPadding, bottomPadding)
}
private fun createBounds(featureCollection: FeatureCollection): LatLngBounds {
val boundsBuilder = LatLngBounds.Builder()
featureCollection.features()?.let {
for (feature in it) {
val point = feature.geometry() as Point
boundsBuilder.include(LatLng(point.latitude(), point.longitude()))
}
}
return boundsBuilder.build()
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
override fun onDestroy() {
super.onDestroy()
mapView.onDestroy()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
mapView.onSaveInstanceState(outState)
}
}
fun Int.toPx(context: Context): Int = (this * context.resources.displayMetrics.density).toInt()

View File

@@ -0,0 +1,120 @@
package com.mapbox.mapboxsdk.testapp.activity.camera;
import android.graphics.Point;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.UiSettings;
import com.mapbox.mapboxsdk.testapp.R;
/**
* Test activity showcasing the zoom Camera API.
* <p>
* This includes zoomIn, zoomOut, zoomTo, zoomBy (center and custom focal point).
* </p>
*/
public class ManualZoomActivity extends AppCompatActivity {
private MapboxMap mapboxMap;
private MapView mapView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_manual_zoom);
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(mapboxMap -> {
ManualZoomActivity.this.mapboxMap = mapboxMap;
mapboxMap.setStyle(new Style.Builder().fromUri(Style.SATELLITE));
UiSettings uiSettings = ManualZoomActivity.this.mapboxMap.getUiSettings();
uiSettings.setAllGesturesEnabled(false);
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_zoom, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_zoom_in:
mapboxMap.animateCamera(CameraUpdateFactory.zoomIn());
return true;
case R.id.action_zoom_out:
mapboxMap.animateCamera(CameraUpdateFactory.zoomOut());
return true;
case R.id.action_zoom_by:
mapboxMap.animateCamera(CameraUpdateFactory.zoomBy(2));
return true;
case R.id.action_zoom_to:
mapboxMap.animateCamera(CameraUpdateFactory.zoomTo(2));
return true;
case R.id.action_zoom_to_point:
View view = getWindow().getDecorView();
mapboxMap.animateCamera(
CameraUpdateFactory.zoomBy(1, new Point(view.getMeasuredWidth() / 4, view.getMeasuredHeight() / 4)));
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}

View File

@@ -0,0 +1,99 @@
package com.mapbox.mapboxsdk.testapp.activity.camera;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import com.mapbox.mapboxsdk.maps.Style;
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.testapp.R;
import timber.log.Timber;
/**
* Test activity showcasing using maximum and minimum zoom levels to restrict camera movement.
*/
public class MaxMinZoomActivity extends AppCompatActivity implements OnMapReadyCallback {
private MapView mapView;
private MapboxMap mapboxMap;
private MapboxMap.OnMapClickListener clickListener = new MapboxMap.OnMapClickListener() {
@Override
public boolean onMapClick(@NonNull LatLng point) {
if (mapboxMap != null) {
mapboxMap.setStyle(new Style.Builder().fromUri(Style.OUTDOORS));
}
return true;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maxmin_zoom);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
mapView.addOnDidFinishLoadingStyleListener(() -> Timber.d("Style Loaded"));
}
@Override
public void onMapReady(@NonNull final MapboxMap map) {
mapboxMap = map;
mapboxMap.setStyle(Style.MAPBOX_STREETS);
mapboxMap.setMinZoomPreference(3);
mapboxMap.setMaxZoomPreference(5);
mapboxMap.addOnMapClickListener(clickListener);
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mapboxMap != null) {
mapboxMap.removeOnMapClickListener(clickListener);
}
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}

View File

@@ -0,0 +1,158 @@
package com.mapbox.mapboxsdk.testapp.activity.camera;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.StringRes;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import android.widget.SeekBar;
import android.widget.TextView;
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.maps.UiSettings;
import com.mapbox.mapboxsdk.testapp.R;
/**
* Test activity showcasing using the scrollBy Camera API by moving x,y pixels above Grenada, Spain.
*/
public class ScrollByActivity extends AppCompatActivity implements OnMapReadyCallback {
public static final int MULTIPLIER_PER_PIXEL = 50;
private MapView mapView;
private MapboxMap mapboxMap;
private SeekBar seekBarX;
private SeekBar seekBarY;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scroll_by);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setDisplayShowHomeEnabled(true);
}
seekBarX = findViewById(R.id.seekbar_move_x);
TextView textViewX = findViewById(R.id.textview_x);
seekBarX.setOnSeekBarChangeListener(new PixelBarChangeListener(textViewX, R.string.scrollby_x_value));
seekBarY = findViewById(R.id.seekbar_move_y);
TextView textViewY = findViewById(R.id.textview_y);
seekBarY.setOnSeekBarChangeListener(new PixelBarChangeListener(textViewY, R.string.scrollby_y_value));
mapView = findViewById(R.id.mapView);
mapView.setTag(true);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
}
@Override
public void onMapReady(@NonNull MapboxMap map) {
mapboxMap = map;
mapboxMap.setStyle(Style.DARK);
UiSettings uiSettings = mapboxMap.getUiSettings();
uiSettings.setLogoEnabled(false);
uiSettings.setAttributionEnabled(false);
FloatingActionButton fab = findViewById(R.id.fab);
fab.setColorFilter(ContextCompat.getColor(ScrollByActivity.this, R.color.primary));
fab.setOnClickListener(view -> mapboxMap.scrollBy(
seekBarX.getProgress() * MULTIPLIER_PER_PIXEL,
seekBarY.getProgress() * MULTIPLIER_PER_PIXEL)
);
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private static class PixelBarChangeListener implements SeekBar.OnSeekBarChangeListener {
@StringRes
private int prefixTextResource;
private TextView valueView;
PixelBarChangeListener(@NonNull TextView textView, @StringRes int textRes) {
valueView = textView;
prefixTextResource = textRes;
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
int value = progress * ScrollByActivity.MULTIPLIER_PER_PIXEL;
valueView.setText(String.format(seekBar.getResources().getString(prefixTextResource), value));
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
}
}

View File

@@ -0,0 +1,143 @@
package com.mapbox.mapboxsdk.testapp.activity.customlayer;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
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.Style;
import com.mapbox.mapboxsdk.style.layers.CustomLayer;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.model.customlayer.ExampleCustomLayer;
/**
* Test activity showcasing the Custom Layer API
* <p>
* Note: experimental API, do not use.
* </p>
*/
public class CustomLayerActivity extends AppCompatActivity {
private MapboxMap mapboxMap;
private MapView mapView;
private CustomLayer customLayer;
private FloatingActionButton fab;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_custom_layer);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(map -> {
mapboxMap = map;
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(39.91448, -243.60947), 10));
mapboxMap.setStyle(Style.MAPBOX_STREETS, style -> initFab());
});
}
private void initFab() {
fab = findViewById(R.id.fab);
fab.setColorFilter(ContextCompat.getColor(this, R.color.primary));
fab.setOnClickListener(view -> {
if (mapboxMap != null) {
swapCustomLayer();
}
});
}
private void swapCustomLayer() {
Style style = mapboxMap.getStyle();
if (customLayer != null) {
style.removeLayer(customLayer);
customLayer = null;
fab.setImageResource(R.drawable.ic_layers);
} else {
customLayer = new CustomLayer("custom",
ExampleCustomLayer.createContext());
style.addLayerBelow(customLayer, "building");
fab.setImageResource(R.drawable.ic_layers_clear);
}
}
private void updateLayer() {
if (customLayer != null) {
customLayer.update();
}
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_custom_layer, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_update_layer:
updateLayer();
return true;
case R.id.action_set_color_red:
ExampleCustomLayer.setColor(1, 0, 0, 1);
return true;
case R.id.action_set_color_green:
ExampleCustomLayer.setColor(0, 1, 0, 1);
return true;
case R.id.action_set_color_blue:
ExampleCustomLayer.setColor(0, 0, 1, 1);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}

View File

@@ -0,0 +1,79 @@
package com.mapbox.mapboxsdk.testapp.activity.espresso;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
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.testapp.R;
public class DeviceIndependentTestActivity extends AppCompatActivity implements OnMapReadyCallback {
public MapView mapView;
protected MapboxMap mapboxMap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera_test);
// Initialize map as normal
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
}
@Override
public void onMapReady(@NonNull MapboxMap map) {
mapboxMap = map;
mapboxMap.setStyle(Style.MAPBOX_STREETS);
}
public MapboxMap getMapboxMap() {
return mapboxMap;
}
@Override
public void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
public void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}

View File

@@ -0,0 +1,66 @@
package com.mapbox.mapboxsdk.testapp.activity.espresso;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.testapp.R;
/**
* Base activity for instrumentation testing.
*/
public class EspressoTestActivity extends AppCompatActivity {
public MapView mapView;
protected MapboxMap mapboxMap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_espresso_test);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
}
@Override
public void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
public void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}

View File

@@ -0,0 +1,66 @@
package com.mapbox.mapboxsdk.testapp.activity.espresso
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
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.testapp.R
/**
* Test activity used for instrumentation tests that require a specific device size.
*/
class PixelTestActivity : AppCompatActivity(), OnMapReadyCallback {
lateinit var mapView: MapView
lateinit var mapboxMap: MapboxMap
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_pixel_test)
mapView = findViewById(R.id.mapView)
mapView.onCreate(savedInstanceState)
mapView.getMapAsync(this)
}
override fun onMapReady(map: MapboxMap) {
mapboxMap = map
mapboxMap.setStyle(Style.MAPBOX_STREETS)
}
public override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
public override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
mapView.onSaveInstanceState(outState)
}
override fun onDestroy() {
super.onDestroy()
mapView.onDestroy()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
}

View File

@@ -0,0 +1,154 @@
package com.mapbox.mapboxsdk.testapp.activity.feature;
import android.graphics.PointF;
import android.graphics.RectF;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
import com.google.gson.JsonElement;
import com.mapbox.geojson.Feature;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.utils.NavUtils;
import timber.log.Timber;
import java.util.List;
import java.util.Map;
/**
* Test activity showcasing using the query rendered features API to count features in a rectangle.
*/
public class QueryRenderedFeaturesBoxCountActivity extends AppCompatActivity {
public MapView mapView;
private MapboxMap mapboxMap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_query_features_box);
final View selectionBox = findViewById(R.id.selection_box);
// Initialize map as normal
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(mapboxMap -> {
QueryRenderedFeaturesBoxCountActivity.this.mapboxMap = mapboxMap;
mapboxMap.setStyle(new Style.Builder().fromUri(Style.MAPBOX_STREETS));
selectionBox.setOnClickListener(view -> {
// Query
int top = selectionBox.getTop() - mapView.getTop();
int left = selectionBox.getLeft() - mapView.getLeft();
RectF box = new RectF(left, top, left + selectionBox.getWidth(), top + selectionBox.getHeight());
Timber.i("Querying box %s", box);
List<Feature> features = mapboxMap.queryRenderedFeatures(box);
// Show count
Toast.makeText(
QueryRenderedFeaturesBoxCountActivity.this,
String.format("%s features in box", features.size()),
Toast.LENGTH_SHORT).show();
// Debug output
debugOutput(features);
});
});
}
private void debugOutput(List<Feature> features) {
Timber.i("Got %s features", features.size());
for (Feature feature : features) {
if (feature != null) {
Timber.i("Got feature %s with %s properties and Geometry %s",
feature.id(),
feature.properties() != null ? feature.properties().entrySet().size() : "<null>",
feature.geometry() != null ? feature.geometry().getClass().getSimpleName() : "<null>"
);
if (feature.properties() != null) {
for (Map.Entry<String, JsonElement> entry : feature.properties().entrySet()) {
Timber.i("Prop %s - %s", entry.getKey(), entry.getValue());
}
}
} else {
Timber.i("Got 0 features");
}
}
}
public MapboxMap getMapboxMap() {
return mapboxMap;
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
if (mapboxMap != null) {
// Regression test for #14394
mapboxMap.queryRenderedFeatures(new PointF(0, 0));
}
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
// activity uses singleInstance for testing purposes
// code below provides a default navigation when using the app
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onBackPressed() {
// activity uses singleInstance for testing purposes
// code below provides a default navigation when using the app
NavUtils.navigateHome(this);
}
}

View File

@@ -0,0 +1,130 @@
package com.mapbox.mapboxsdk.testapp.activity.feature;
import android.graphics.Color;
import android.graphics.RectF;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;
import com.mapbox.geojson.Feature;
import com.mapbox.geojson.FeatureCollection;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.style.expressions.Expression;
import com.mapbox.mapboxsdk.style.layers.FillLayer;
import com.mapbox.mapboxsdk.style.layers.Layer;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import com.mapbox.mapboxsdk.testapp.R;
import java.util.List;
import timber.log.Timber;
import static com.mapbox.mapboxsdk.style.expressions.Expression.get;
import static com.mapbox.mapboxsdk.style.expressions.Expression.literal;
import static com.mapbox.mapboxsdk.style.expressions.Expression.lt;
import static com.mapbox.mapboxsdk.style.expressions.Expression.toNumber;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillColor;
/**
* Demo's query rendered features
*/
public class QueryRenderedFeaturesBoxHighlightActivity extends AppCompatActivity {
public MapView mapView;
private MapboxMap mapboxMap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_query_features_box);
final View selectionBox = findViewById(R.id.selection_box);
// Initialize map as normal
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(mapboxMap -> {
QueryRenderedFeaturesBoxHighlightActivity.this.mapboxMap = mapboxMap;
// Add layer / source
final GeoJsonSource source = new GeoJsonSource("highlighted-shapes-source");
final Layer layer = new FillLayer("highlighted-shapes-layer", "highlighted-shapes-source")
.withProperties(fillColor(Color.RED));
selectionBox.setOnClickListener(view -> {
// Query
int top = selectionBox.getTop() - mapView.getTop();
int left = selectionBox.getLeft() - mapView.getLeft();
RectF box = new RectF(left, top, left + selectionBox.getWidth(), top + selectionBox.getHeight());
Timber.i("Querying box %s for buildings", box);
Expression filter = lt(toNumber(get("height")), literal(10));
List<Feature> features = mapboxMap.queryRenderedFeatures(box, filter, "building");
// Show count
Toast.makeText(
QueryRenderedFeaturesBoxHighlightActivity.this,
String.format("%s features in box", features.size()),
Toast.LENGTH_SHORT).show();
// Update source data
source.setGeoJson(FeatureCollection.fromFeatures(features));
});
mapboxMap.setStyle(new Style.Builder()
.fromUri(Style.MAPBOX_STREETS)
.withSource(source)
.withLayer(layer)
);
});
}
public MapboxMap getMapboxMap() {
return mapboxMap;
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}

View File

@@ -0,0 +1,145 @@
package com.mapbox.mapboxsdk.testapp.activity.feature;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.RectF;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;
import com.mapbox.geojson.Feature;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.style.layers.BackgroundLayer;
import com.mapbox.mapboxsdk.style.layers.SymbolLayer;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.utils.ResourceUtils;
import java.io.IOException;
import java.util.List;
import timber.log.Timber;
import static com.mapbox.mapboxsdk.style.expressions.Expression.rgb;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.backgroundColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage;
/**
* Test activity showcasing using the query rendered features API to count Symbols in a rectangle.
*/
public class QueryRenderedFeaturesBoxSymbolCountActivity extends AppCompatActivity {
public MapView mapView;
private MapboxMap mapboxMap;
private Toast toast;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_query_features_box);
final View selectionBox = findViewById(R.id.selection_box);
// Initialize map as normal
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(mapboxMap -> {
QueryRenderedFeaturesBoxSymbolCountActivity.this.mapboxMap = mapboxMap;
try {
String testPoints = ResourceUtils.readRawResource(mapView.getContext(), R.raw.test_points_utrecht);
Bitmap markerImage = BitmapFactory.decodeResource(getResources(), R.drawable.mapbox_marker_icon_default);
mapboxMap.setStyle(new Style.Builder()
.withLayer(
new BackgroundLayer("bg")
.withProperties(
backgroundColor(rgb(120, 161, 226))
)
)
.withLayer(
new SymbolLayer("symbols-layer", "symbols-source")
.withProperties(
iconImage("test-icon")
)
)
.withSource(
new GeoJsonSource("symbols-source", testPoints)
)
.withImage("test-icon", markerImage)
);
} catch (IOException exception) {
exception.printStackTrace();
}
selectionBox.setOnClickListener(view -> {
// Query
int top = selectionBox.getTop() - mapView.getTop();
int left = selectionBox.getLeft() - mapView.getLeft();
RectF box = new RectF(left, top, left + selectionBox.getWidth(), top + selectionBox.getHeight());
Timber.i("Querying box %s", box);
List<Feature> features = mapboxMap.queryRenderedFeatures(box, "symbols-layer");
// Show count
if (toast != null) {
toast.cancel();
}
toast = Toast.makeText(
QueryRenderedFeaturesBoxSymbolCountActivity.this,
String.format("%s features in box", features.size()),
Toast.LENGTH_SHORT);
toast.show();
});
});
}
public MapboxMap getMapboxMap() {
return mapboxMap;
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}

View File

@@ -0,0 +1,244 @@
package com.mapbox.mapboxsdk.testapp.activity.feature;
import android.graphics.Color;
import android.graphics.PointF;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.google.gson.JsonElement;
import com.mapbox.geojson.Feature;
import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.testapp.R;
import java.util.List;
import java.util.Map;
import timber.log.Timber;
/**
* Test activity showcasing using the query rendered features API to query feature properties on Map click.
*/
public class QueryRenderedFeaturesPropertiesActivity extends AppCompatActivity {
public MapView mapView;
private MapboxMap mapboxMap;
private Marker marker;
private MapboxMap.OnMapClickListener mapClickListener = new MapboxMap.OnMapClickListener() {
@Override
public boolean onMapClick(@NonNull LatLng point) {
final float density = getResources().getDisplayMetrics().density;
final PointF pixel = mapboxMap.getProjection().toScreenLocation(point);
Timber.i(
"Requesting features for %sx%s (%sx%s adjusted for density)",
pixel.x, pixel.y, pixel.x / density, pixel.y / density
);
List<Feature> features = mapboxMap.queryRenderedFeatures(pixel);
// Debug output
debugOutput(features);
// Remove any previous markers
if (marker != null) {
mapboxMap.removeMarker(marker);
}
// Add a marker on the clicked point
marker = mapboxMap.addMarker(new CustomMarkerOptions().position(point).features(features));
mapboxMap.selectMarker(marker);
return true;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_query_features_point);
// Initialize map as normal
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(mapboxMap -> {
mapboxMap.setStyle(Style.MAPBOX_STREETS, style -> {
QueryRenderedFeaturesPropertiesActivity.this.mapboxMap = mapboxMap;
// Add custom window adapter
addCustomInfoWindowAdapter(mapboxMap);
// Add a click listener
mapboxMap.addOnMapClickListener(mapClickListener);
});
});
}
private void debugOutput(List<Feature> features) {
Timber.i("Got %s features", features.size());
for (Feature feature : features) {
if (feature != null) {
Timber.i("Got feature %s with %s properties and Geometry %s",
feature.id(),
feature.properties() != null ? feature.properties().entrySet().size() : "<null>",
feature.geometry() != null ? feature.geometry().getClass().getSimpleName() : "<null>"
);
if (feature.properties() != null) {
for (Map.Entry<String, JsonElement> entry : feature.properties().entrySet()) {
Timber.i("Prop %s - %s", entry.getKey(), entry.getValue());
}
}
} else {
Timber.i("Got NULL feature");
}
}
}
private void addCustomInfoWindowAdapter(MapboxMap mapboxMap) {
mapboxMap.setInfoWindowAdapter(new MapboxMap.InfoWindowAdapter() {
private TextView row(String text) {
TextView view = new TextView(QueryRenderedFeaturesPropertiesActivity.this);
view.setText(text);
return view;
}
@Override
public View getInfoWindow(@NonNull Marker marker) {
CustomMarker customMarker = (CustomMarker) marker;
LinearLayout view = new LinearLayout(QueryRenderedFeaturesPropertiesActivity.this);
view.setOrientation(LinearLayout.VERTICAL);
view.setBackgroundColor(Color.WHITE);
if (customMarker.features.size() > 0) {
view.addView(row(String.format("Found %s features", customMarker.features.size())));
Feature feature = customMarker.features.get(0);
for (Map.Entry<String, JsonElement> prop : feature.properties().entrySet()) {
view.addView(row(String.format("%s: %s", prop.getKey(), prop.getValue())));
}
} else {
view.addView(row("No features here"));
}
return view;
}
});
}
public MapboxMap getMapboxMap() {
return mapboxMap;
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mapboxMap != null) {
mapboxMap.removeOnMapClickListener(mapClickListener);
}
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
private static class CustomMarker extends Marker {
private final List<Feature> features;
CustomMarker(BaseMarkerOptions baseMarkerOptions, List<Feature> features) {
super(baseMarkerOptions);
this.features = features;
}
}
private static class CustomMarkerOptions extends BaseMarkerOptions<CustomMarker, CustomMarkerOptions> {
private List<Feature> features;
public CustomMarkerOptions features(List<Feature> features) {
this.features = features;
return this;
}
CustomMarkerOptions() {
}
private CustomMarkerOptions(Parcel in) {
// Should implement this
}
@Override
public CustomMarkerOptions getThis() {
return this;
}
@Override
public CustomMarker getMarker() {
return new CustomMarker(this, features);
}
public static final Parcelable.Creator<CustomMarkerOptions> CREATOR =
new Parcelable.Creator<CustomMarkerOptions>() {
public CustomMarkerOptions createFromParcel(Parcel in) {
return new CustomMarkerOptions(in);
}
public CustomMarkerOptions[] newArray(int size) {
return new CustomMarkerOptions[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel out, int flags) {
// Should implement this
}
}
}

View File

@@ -0,0 +1,134 @@
package com.mapbox.mapboxsdk.testapp.activity.feature;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;
import com.google.gson.JsonObject;
import com.mapbox.geojson.Feature;
import com.mapbox.geojson.FeatureCollection;
import com.mapbox.geojson.Point;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.style.expressions.Expression;
import com.mapbox.mapboxsdk.style.layers.CircleLayer;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import com.mapbox.mapboxsdk.testapp.R;
import java.util.List;
import static com.mapbox.mapboxsdk.style.expressions.Expression.eq;
import static com.mapbox.mapboxsdk.style.expressions.Expression.get;
import static com.mapbox.mapboxsdk.style.expressions.Expression.literal;
import static com.mapbox.mapboxsdk.style.expressions.Expression.neq;
/**
* Test activity showcasing using the query source features API to query feature counts
*/
public class QuerySourceFeaturesActivity extends AppCompatActivity {
public MapView mapView;
private MapboxMap mapboxMap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_query_source_features);
// Initialize map as normal
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(map -> {
this.mapboxMap = map;
mapboxMap.getStyle(this::initStyle);
mapboxMap.setStyle(Style.MAPBOX_STREETS);
});
}
private void initStyle(Style style) {
JsonObject properties = new JsonObject();
properties.addProperty("key1", "value1");
final GeoJsonSource source = new GeoJsonSource("test-source",
FeatureCollection.fromFeatures(new Feature[] {
Feature.fromGeometry(Point.fromLngLat(17.1, 51), properties),
Feature.fromGeometry(Point.fromLngLat(17.2, 51), properties),
Feature.fromGeometry(Point.fromLngLat(17.3, 51), properties),
Feature.fromGeometry(Point.fromLngLat(17.4, 51), properties),
}));
style.addSource(source);
Expression visible = eq(get("key1"), literal("value1"));
Expression invisible = neq(get("key1"), literal("value1"));
CircleLayer layer = new CircleLayer("test-layer", source.getId())
.withFilter(visible);
style.addLayer(layer);
// Add a click listener
mapboxMap.addOnMapClickListener(point -> {
// Query
List<Feature> features = source.querySourceFeatures(eq(get("key1"), literal("value1")));
Toast.makeText(QuerySourceFeaturesActivity.this, String.format("Found %s features",
features.size()), Toast.LENGTH_SHORT).show();
return false;
});
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setColorFilter(ContextCompat.getColor(this, R.color.primary));
fab.setOnClickListener(view -> {
Expression visibility = layer.getFilter();
if (visibility != null && visibility.equals(visible)) {
layer.setFilter(invisible);
fab.setImageResource(R.drawable.ic_layers_clear);
} else {
layer.setFilter(visible);
fab.setImageResource(R.drawable.ic_layers);
}
});
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}

View File

@@ -0,0 +1,67 @@
package com.mapbox.mapboxsdk.testapp.activity.fragment
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import com.mapbox.mapboxsdk.maps.MapboxMap
import com.mapbox.mapboxsdk.maps.Style
import com.mapbox.mapboxsdk.maps.SupportMapFragment
import com.mapbox.mapboxsdk.testapp.R
import com.mapbox.mapboxsdk.testapp.utils.NavUtils
import kotlinx.android.synthetic.main.activity_backstack_fragment.*
/**
* Test activity showcasing using the MapFragment API as part of a backstacked fragment.
*/
class FragmentBackStackActivity : AppCompatActivity() {
companion object {
private const val FRAGMENT_TAG = "map_fragment"
}
private lateinit var mapFragment: SupportMapFragment
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_backstack_fragment)
if (savedInstanceState == null) {
mapFragment = SupportMapFragment.newInstance()
mapFragment.getMapAsync { initMap(it) }
supportFragmentManager.beginTransaction().apply {
add(R.id.container, mapFragment, FRAGMENT_TAG)
}.commit()
} else {
supportFragmentManager.findFragmentByTag(FRAGMENT_TAG)?.also { fragment ->
if (fragment is SupportMapFragment) {
fragment.getMapAsync { initMap(it) }
}
}
}
button.setOnClickListener { handleClick() }
}
private fun initMap(mapboxMap: MapboxMap) {
mapboxMap.setStyle(Style.SATELLITE) {
mapboxMap.setPadding(300, 300, 300, 300)
}
}
private fun handleClick() {
supportFragmentManager.beginTransaction().apply {
replace(R.id.container, NestedViewPagerActivity.ItemAdapter.EmptyFragment())
addToBackStack("map_empty_fragment")
}.commit()
}
override fun onBackPressed() {
if (supportFragmentManager.backStackEntryCount == 0) {
// activity uses singleInstance for testing purposes
// code below provides a default navigation when using the app
NavUtils.navigateHome(this)
} else {
super.onBackPressed()
}
}
}

View File

@@ -0,0 +1,95 @@
package com.mapbox.mapboxsdk.testapp.activity.fragment;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapFragment;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.testapp.R;
/**
* Test activity showcasing using the MapFragment API using SDK Fragments.
* <p>
* Uses MapboxMapOptions to initialise the Fragment.
* </p>
*/
public class MapFragmentActivity extends AppCompatActivity implements MapFragment.OnMapViewReadyCallback,
OnMapReadyCallback, MapView.OnDidFinishRenderingFrameListener {
private static final String TAG = "com.mapbox.map";
private MapboxMap mapboxMap;
private MapView mapView;
private boolean initialCameraAnimation = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_fragment);
MapFragment mapFragment;
if (savedInstanceState == null) {
mapFragment = MapFragment.newInstance(createFragmentOptions());
getFragmentManager()
.beginTransaction()
.add(R.id.fragment_container, mapFragment, TAG)
.commit();
} else {
mapFragment = (MapFragment) getFragmentManager().findFragmentByTag(TAG);
}
mapFragment.getMapAsync(this);
}
private MapboxMapOptions createFragmentOptions() {
MapboxMapOptions options = MapboxMapOptions.createFromAttributes(this, null);
options.scrollGesturesEnabled(false);
options.zoomGesturesEnabled(false);
options.tiltGesturesEnabled(false);
options.rotateGesturesEnabled(false);
options.debugActive(false);
LatLng dc = new LatLng(38.90252, -77.02291);
options.minZoomPreference(9);
options.maxZoomPreference(11);
options.camera(new CameraPosition.Builder()
.target(dc)
.zoom(11)
.build());
return options;
}
@Override
public void onMapViewReady(MapView map) {
mapView = map;
mapView.addOnDidFinishRenderingFrameListener(this);
}
@Override
public void onMapReady(@NonNull MapboxMap map) {
mapboxMap = map;
mapboxMap.setStyle(Style.OUTDOORS);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.removeOnDidFinishRenderingFrameListener(this);
}
@Override
public void onDidFinishRenderingFrame(boolean fully) {
if (initialCameraAnimation && fully && mapboxMap != null) {
mapboxMap.animateCamera(
CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder().tilt(45.0).build()), 5000);
initialCameraAnimation = false;
}
}
}

View File

@@ -0,0 +1,31 @@
package com.mapbox.mapboxsdk.testapp.activity.fragment;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.maps.SupportMapFragment;
import com.mapbox.mapboxsdk.testapp.R;
/**
* Test Activity showcasing using multiple static map fragments in one layout.
*/
public class MultiMapActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_multi_map);
FragmentManager fragmentManager = getSupportFragmentManager();
initFragmentStyle(fragmentManager, R.id.map1, Style.MAPBOX_STREETS);
initFragmentStyle(fragmentManager, R.id.map2, Style.LIGHT);
initFragmentStyle(fragmentManager, R.id.map3, Style.SATELLITE_STREETS);
initFragmentStyle(fragmentManager, R.id.map4, Style.DARK);
}
private void initFragmentStyle(FragmentManager fragmentManager, int fragmentId, String styleId) {
((SupportMapFragment) fragmentManager.findFragmentById(fragmentId))
.getMapAsync(mapboxMap -> mapboxMap.setStyle(styleId));
}
}

View File

@@ -0,0 +1,166 @@
package com.mapbox.mapboxsdk.testapp.activity.fragment
import android.annotation.SuppressLint
import android.content.Context
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentManager
import android.support.v4.app.FragmentStatePagerAdapter
import android.support.v4.view.ViewPager
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import com.mapbox.mapboxsdk.camera.CameraPosition
import com.mapbox.mapboxsdk.geometry.LatLng
import com.mapbox.mapboxsdk.maps.MapboxMapOptions
import com.mapbox.mapboxsdk.maps.Style
import com.mapbox.mapboxsdk.maps.SupportMapFragment
import com.mapbox.mapboxsdk.testapp.R
import kotlinx.android.synthetic.main.activity_recyclerview.*
/**
* TestActivity showcasing how to integrate a MapView in a RecyclerView.
* <p>
* It requires calling the correct lifecycle methods when detaching and attaching the View to
* the RecyclerView with onViewAttachedToWindow and onViewDetachedFromWindow.
* </p>
*/
@SuppressLint("ClickableViewAccessibility")
class NestedViewPagerActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_recyclerview)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = ItemAdapter(this, LayoutInflater.from(this), supportFragmentManager)
}
class ItemAdapter(private val context: Context, private val inflater: LayoutInflater, private val fragmentManager: FragmentManager) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private val items = listOf(
"one", "two", "three", ViewPagerItem(), "four", "five", "six", "seven", "eight", "nine", "ten",
"eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen",
"nineteen", "twenty", "twenty-one"
)
private var mapHolder: ViewPagerHolder? = null
companion object {
const val TYPE_VIEWPAGER = 0
const val TYPE_TEXT = 1
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == TYPE_VIEWPAGER) {
val viewPager = inflater.inflate(R.layout.item_viewpager, parent, false) as ViewPager
mapHolder = ViewPagerHolder(context, viewPager, fragmentManager)
return mapHolder as ViewPagerHolder
} else {
TextHolder(inflater.inflate(android.R.layout.simple_list_item_1, parent, false) as TextView)
}
}
override fun getItemCount(): Int {
return items.count()
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder.itemViewType == TYPE_TEXT) {
val textHolder = holder as TextHolder
textHolder.bind(items[position] as String)
}
}
override fun getItemViewType(position: Int): Int {
return if (items[position] is ViewPagerItem) {
TYPE_VIEWPAGER
} else {
TYPE_TEXT
}
}
class TextHolder(val textView: TextView) : RecyclerView.ViewHolder(textView) {
fun bind(item: String) {
textView.text = item
}
}
class ViewPagerItem
class ViewPagerHolder(context: Context, private val viewPager: ViewPager, fragmentManager: FragmentManager) : RecyclerView.ViewHolder(viewPager) {
init {
viewPager.adapter = MapPagerAdapter(context, fragmentManager)
viewPager.setOnTouchListener { view, motionEvent ->
// Disallow the touch request for recyclerView scroll
view.parent.requestDisallowInterceptTouchEvent(true)
viewPager.onTouchEvent(motionEvent)
false
}
}
}
class MapPagerAdapter(private val context: Context, fm: FragmentManager?) : FragmentStatePagerAdapter(fm) {
override fun getItem(position: Int): Fragment {
val options = MapboxMapOptions.createFromAttributes(context)
options.textureMode(true)
options.doubleTapGesturesEnabled(false)
options.rotateGesturesEnabled(false)
options.tiltGesturesEnabled(false)
options.scrollGesturesEnabled(false)
options.zoomGesturesEnabled(false)
when (position) {
0 -> {
options.camera(CameraPosition.Builder().target(LatLng(34.920526, 102.634774)).zoom(3.0).build())
val fragment = SupportMapFragment.newInstance(options)
fragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.MAPBOX_STREETS) }
return fragment
}
1 -> {
return EmptyFragment.newInstance()
}
2 -> {
options.camera(CameraPosition.Builder().target(LatLng(62.326440, 92.764913)).zoom(3.0).build())
val fragment = SupportMapFragment.newInstance(options)
fragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.DARK) }
return fragment
}
3 -> {
return EmptyFragment.newInstance()
}
4 -> {
options.camera(CameraPosition.Builder().target(LatLng(-25.007786, 133.623852)).zoom(3.0).build())
val fragment = SupportMapFragment.newInstance(options)
fragment.getMapAsync { mapboxMap -> mapboxMap.setStyle(Style.SATELLITE) }
return fragment
}
5 -> {
return EmptyFragment.newInstance()
}
}
throw IllegalAccessError()
}
override fun getCount(): Int {
return 6
}
}
class EmptyFragment : Fragment() {
companion object {
fun newInstance(): EmptyFragment {
return EmptyFragment()
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
val textView = TextView(inflater.context)
textView.text = "This is an empty Fragment"
return textView
}
}
}
}

View File

@@ -0,0 +1,96 @@
package com.mapbox.mapboxsdk.testapp.activity.fragment;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapFragment;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.maps.SupportMapFragment;
import com.mapbox.mapboxsdk.testapp.R;
/**
* Test activity showcasing using the MapFragment API using Support Library Fragments.
* <p>
* Uses MapboxMapOptions to initialise the Fragment.
* </p>
*/
public class SupportMapFragmentActivity extends AppCompatActivity implements MapFragment.OnMapViewReadyCallback,
OnMapReadyCallback, MapView.OnDidFinishRenderingFrameListener {
private static final String TAG = "com.mapbox.map";
private MapboxMap mapboxMap;
private MapView mapView;
private boolean initialCameraAnimation = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_fragment);
SupportMapFragment mapFragment;
if (savedInstanceState == null) {
mapFragment = SupportMapFragment.newInstance(createFragmentOptions());
getSupportFragmentManager()
.beginTransaction()
.add(R.id.fragment_container, mapFragment, TAG)
.commit();
} else {
mapFragment = (SupportMapFragment) getSupportFragmentManager().findFragmentByTag(TAG);
}
mapFragment.getMapAsync(this);
}
private MapboxMapOptions createFragmentOptions() {
MapboxMapOptions options = MapboxMapOptions.createFromAttributes(this, null);
options.scrollGesturesEnabled(false);
options.zoomGesturesEnabled(false);
options.tiltGesturesEnabled(false);
options.rotateGesturesEnabled(false);
options.debugActive(false);
LatLng dc = new LatLng(38.90252, -77.02291);
options.minZoomPreference(9);
options.maxZoomPreference(11);
options.camera(new CameraPosition.Builder()
.target(dc)
.zoom(11)
.build());
return options;
}
@Override
public void onMapViewReady(MapView map) {
mapView = map;
mapView.addOnDidFinishRenderingFrameListener(this);
}
@Override
public void onMapReady(@NonNull MapboxMap map) {
mapboxMap = map;
mapboxMap.setStyle(Style.SATELLITE);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.removeOnDidFinishRenderingFrameListener(this);
}
@Override
public void onDidFinishRenderingFrame(boolean fully) {
if (initialCameraAnimation && fully && mapboxMap != null) {
mapboxMap.animateCamera(
CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder().tilt(45.0).build()), 5000);
initialCameraAnimation = false;
}
}
}

View File

@@ -0,0 +1,102 @@
package com.mapbox.mapboxsdk.testapp.activity.fragment
import android.content.Context
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v4.app.FragmentManager
import android.support.v4.app.FragmentStatePagerAdapter
import android.support.v7.app.AppCompatActivity
import com.mapbox.mapboxsdk.camera.CameraPosition
import com.mapbox.mapboxsdk.geometry.LatLng
import com.mapbox.mapboxsdk.maps.MapboxMapOptions
import com.mapbox.mapboxsdk.maps.Style
import com.mapbox.mapboxsdk.maps.SupportMapFragment
import com.mapbox.mapboxsdk.testapp.R
import kotlinx.android.synthetic.main.activity_viewpager.*
/**
* Test activity showcasing using the Android SDK ViewPager API to show MapFragments.
*/
class ViewPagerActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_viewpager)
viewPager.adapter = MapFragmentAdapter(this, supportFragmentManager)
}
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreInstanceState(savedInstanceState)
val currentPosition = viewPager.currentItem
val offscreenLimit = viewPager.offscreenPageLimit
for (i in currentPosition - offscreenLimit..currentPosition + offscreenLimit) {
if (i < 0 || i > viewPager.adapter?.count ?: 0) {
continue
}
val mapFragment = viewPager.adapter?.instantiateItem(viewPager, i) as SupportMapFragment
mapFragment.getMapAsync(i)
}
}
internal class MapFragmentAdapter(private val context: Context, fragmentManager: FragmentManager) : FragmentStatePagerAdapter(fragmentManager) {
override fun getCount(): Int {
return NUM_ITEMS
}
override fun getItem(position: Int): Fragment? {
val options = MapboxMapOptions.createFromAttributes(context)
options.textureMode(true)
options.camera(
CameraPosition.Builder()
.zoom(3.0)
.target(
when (position) {
0 -> {
LatLng(34.920526, 102.634774)
}
1 -> {
LatLng(62.326440, 92.764913)
}
2 -> {
LatLng(-25.007786, 133.623852)
}
3 -> {
LatLng(62.326440, 92.764913)
}
else -> {
LatLng(34.920526, 102.634774)
}
}
)
.build())
val fragment = SupportMapFragment.newInstance(options)
fragment.getMapAsync(position)
return fragment
}
override fun getPageTitle(position: Int): CharSequence? {
return "Page $position"
}
companion object {
private const val NUM_ITEMS = 5
}
}
}
fun SupportMapFragment.getMapAsync(index: Int) {
this.getMapAsync {
it.setStyle(
when (index) {
0 -> Style.MAPBOX_STREETS
1 -> Style.DARK
2 -> Style.SATELLITE
3 -> Style.LIGHT
4 -> Style.TRAFFIC_NIGHT
else -> Style.MAPBOX_STREETS
}
)
}
}

View File

@@ -0,0 +1,93 @@
package com.mapbox.mapboxsdk.testapp.activity.imagegenerator;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.support.v4.print.PrintHelper;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.testapp.R;
/**
* Test activity showcasing using the Snaphot API to print a Map.
*/
public class PrintActivity extends AppCompatActivity implements MapboxMap.SnapshotReadyCallback {
private MapView mapView;
private MapboxMap mapboxMap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_print);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this::initMap);
final View fab = findViewById(R.id.fab);
if (fab != null) {
fab.setOnClickListener(view -> {
if (mapboxMap != null && mapboxMap.getStyle() != null) {
mapboxMap.snapshot(PrintActivity.this);
}
});
}
}
private void initMap(MapboxMap mapboxMap) {
this.mapboxMap = mapboxMap;
mapboxMap.setStyle(Style.MAPBOX_STREETS);
}
@Override
public void onSnapshotReady(Bitmap snapshot) {
PrintHelper photoPrinter = new PrintHelper(this);
photoPrinter.setScaleMode(PrintHelper.SCALE_MODE_FIT);
photoPrinter.printBitmap("map.jpg - mapbox print job", snapshot);
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}

View File

@@ -0,0 +1,89 @@
package com.mapbox.mapboxsdk.testapp.activity.imagegenerator
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import com.mapbox.mapboxsdk.log.Logger
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.testapp.R
import kotlinx.android.synthetic.main.activity_snapshot.*
import timber.log.Timber
/**
* Test activity showcasing the Snapshot API to create and display a bitmap of the current shown Map.
*/
class SnapshotActivity : AppCompatActivity(), OnMapReadyCallback {
private lateinit var mapboxMap: MapboxMap
private val idleListener = object : MapView.OnDidFinishRenderingFrameListener {
override fun onDidFinishRenderingFrame(fully: Boolean) {
if (fully) {
mapView.removeOnDidFinishRenderingFrameListener(this)
Logger.v(TAG, LOG_MESSAGE)
mapboxMap.snapshot { snapshot ->
imageView.setImageBitmap(snapshot)
mapView.addOnDidFinishRenderingFrameListener(this)
}
}
}
}
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_snapshot)
mapView.onCreate(savedInstanceState)
mapView.getMapAsync(this)
}
override fun onMapReady(map: MapboxMap) {
mapboxMap = map
mapboxMap.setStyle(Style.Builder().fromUri(Style.OUTDOORS)) { mapView.addOnDidFinishRenderingFrameListener(idleListener) }
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapboxMap.snapshot {
Timber.e("Regression test for https://github.com/mapbox/mapbox-gl-native/pull/11358")
}
mapView.onPause()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
public override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
mapView.onSaveInstanceState(outState)
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
public override fun onDestroy() {
super.onDestroy()
mapView.removeOnDidFinishRenderingFrameListener(idleListener)
mapView.onDestroy()
}
companion object {
const val TAG = "Mbgl-SnapshotActivity"
const val LOG_MESSAGE = "OnSnapshot"
}
}

View File

@@ -0,0 +1,158 @@
package com.mapbox.mapboxsdk.testapp.activity.infowindow;
import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.content.res.ResourcesCompat;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
import com.mapbox.mapboxsdk.annotations.InfoWindow;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
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.testapp.R;
import com.mapbox.mapboxsdk.testapp.utils.IconUtils;
import java.util.Locale;
/**
* Test activity showcasing how to dynamically update InfoWindow when Using an MapboxMap.InfoWindowAdapter.
*/
public class DynamicInfoWindowAdapterActivity extends AppCompatActivity implements OnMapReadyCallback {
private static final LatLng PARIS = new LatLng(48.864716, 2.349014);
private MapboxMap mapboxMap;
private MapView mapView;
private Marker marker;
private MapboxMap.OnMapClickListener mapClickListener = new MapboxMap.OnMapClickListener() {
@Override
public boolean onMapClick(@NonNull LatLng point) {
if (marker == null) {
return false;
}
// Distance from click to marker
double distanceKm = marker.getPosition().distanceTo(point) / 1000;
// Get the info window
final InfoWindow infoWindow = marker.getInfoWindow();
// Get the view from the info window
if (infoWindow != null && infoWindow.getView() != null) {
// Set the new text on the text view in the info window
TextView textView = (TextView) infoWindow.getView();
textView.setText(String.format(Locale.getDefault(), "%.2fkm", distanceKm));
// Update the info window position (as the text length changes)
textView.post(infoWindow::update);
}
return true;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_infowindow_adapter);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
}
@Override
public void onMapReady(@NonNull MapboxMap map) {
mapboxMap = map;
map.setStyle(Style.MAPBOX_STREETS);
// Add info window adapter
addCustomInfoWindowAdapter(mapboxMap);
// Keep info windows open on click
mapboxMap.getUiSettings().setDeselectMarkersOnTap(false);
// Add a marker
marker = addMarker(mapboxMap);
mapboxMap.selectMarker(marker);
// On map click, change the info window contents
mapboxMap.addOnMapClickListener(mapClickListener);
// Focus on Paris
mapboxMap.animateCamera(CameraUpdateFactory.newLatLng(PARIS));
}
private Marker addMarker(MapboxMap mapboxMap) {
return mapboxMap.addMarker(
new MarkerOptions()
.position(PARIS)
.icon(IconUtils.drawableToIcon(this, R.drawable.ic_location_city,
ResourcesCompat.getColor(getResources(), R.color.mapbox_blue, getTheme()))
));
}
private void addCustomInfoWindowAdapter(final MapboxMap mapboxMap) {
final int padding = (int) getResources().getDimension(R.dimen.attr_margin);
mapboxMap.setInfoWindowAdapter(marker -> {
TextView textView = new TextView(DynamicInfoWindowAdapterActivity.this);
textView.setText(marker.getTitle());
textView.setBackgroundColor(Color.WHITE);
textView.setText(R.string.action_calculate_distance);
textView.setPadding(padding, padding, padding, padding);
return textView;
});
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mapboxMap != null) {
mapboxMap.removeOnMapClickListener(mapClickListener);
}
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}

View File

@@ -0,0 +1,199 @@
package com.mapbox.mapboxsdk.testapp.activity.infowindow;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
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.testapp.R;
import java.text.DecimalFormat;
/**
* Test activity showcasing using the InfoWindow API above Washington D.C.
* <p>
* Allows to test mulitple concurrently open InfoWindows.
* </p>
*/
public class InfoWindowActivity extends AppCompatActivity
implements OnMapReadyCallback, MapboxMap.OnInfoWindowCloseListener, MapboxMap.OnInfoWindowClickListener,
MapboxMap.OnInfoWindowLongClickListener {
private MapboxMap mapboxMap;
private MapView mapView;
private Marker customMarker;
private MapboxMap.OnMapLongClickListener mapLongClickListener = new MapboxMap.OnMapLongClickListener() {
@Override
public boolean onMapLongClick(@NonNull LatLng point) {
if (customMarker != null) {
// Remove previous added marker
mapboxMap.removeAnnotation(customMarker);
customMarker = null;
}
// Add marker on long click location with default marker image
customMarker = mapboxMap.addMarker(new MarkerOptions()
.title("Custom Marker")
.snippet(new DecimalFormat("#.#####").format(point.getLatitude()) + ", "
+ new DecimalFormat("#.#####").format(point.getLongitude()))
.position(point));
return true;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_infowindow);
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
}
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
this.mapboxMap = mapboxMap;
mapboxMap.setStyle(Style.MAPBOX_STREETS, style -> {
addMarkers();
addInfoWindowListeners();
});
}
private void addMarkers() {
mapboxMap.addMarker(new MarkerOptions()
.title("Intersection")
.snippet("H St NW with 15th St NW")
.position(new LatLng(38.9002073, -77.03364419)));
mapboxMap.addMarker(new MarkerOptions().title("Intersection")
.snippet("E St NW with 17th St NW")
.position(new LatLng(38.8954236, -77.0394623)));
mapboxMap.addMarker(new MarkerOptions().title("The Ellipse").position(new LatLng(38.89393, -77.03654)));
mapboxMap.addMarker(new MarkerOptions().position(new LatLng(38.89596, -77.03434)));
mapboxMap.addMarker(new MarkerOptions().snippet("Lafayette Square").position(new LatLng(38.89949, -77.03656)));
Marker marker = mapboxMap.addMarker(new MarkerOptions()
.title("White House")
.snippet("The official residence and principal workplace of the President of the United States, "
+ "located at 1600 Pennsylvania Avenue NW in Washington, D.C. It has been the residence of every"
+ "U.S. president since John Adams in 1800.")
.position(new LatLng(38.897705003219784, -77.03655168667463)));
// open InfoWindow at startup
mapboxMap.selectMarker(marker);
}
private void addInfoWindowListeners() {
mapboxMap.setOnInfoWindowCloseListener(this);
mapboxMap.addOnMapLongClickListener(mapLongClickListener);
mapboxMap.setOnInfoWindowClickListener(this);
mapboxMap.setOnInfoWindowLongClickListener(this);
}
private void toggleConcurrentInfoWindow(boolean allowConcurrentInfoWindow) {
mapboxMap.deselectMarkers();
mapboxMap.setAllowConcurrentMultipleOpenInfoWindows(allowConcurrentInfoWindow);
}
private void toggleDeselectMarkersOnTap(boolean deselectMarkersOnTap) {
mapboxMap.getUiSettings().setDeselectMarkersOnTap(deselectMarkersOnTap);
}
@Override
public boolean onInfoWindowClick(@NonNull Marker marker) {
Toast.makeText(getApplicationContext(), "OnClick: " + marker.getTitle(), Toast.LENGTH_LONG).show();
// returning true will leave the info window open
return false;
}
@Override
public void onInfoWindowClose(Marker marker) {
Toast.makeText(getApplicationContext(), "OnClose: " + marker.getTitle(), Toast.LENGTH_LONG).show();
}
@Override
public void onInfoWindowLongClick(Marker marker) {
Toast.makeText(getApplicationContext(), "OnLongClick: " + marker.getTitle(), Toast.LENGTH_LONG).show();
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mapboxMap != null) {
mapboxMap.removeOnMapLongClickListener(mapLongClickListener);
}
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_infowindow, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_toggle_concurrent_infowindow:
toggleConcurrentInfoWindow(!item.isChecked());
item.setChecked(!item.isChecked());
return true;
case R.id.action_toggle_deselect_markers_on_tap:
toggleDeselectMarkersOnTap(!item.isChecked());
item.setChecked(!item.isChecked());
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}

View File

@@ -0,0 +1,128 @@
package com.mapbox.mapboxsdk.testapp.activity.infowindow;
import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;
import com.mapbox.mapboxsdk.annotations.Icon;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.model.annotations.CityStateMarker;
import com.mapbox.mapboxsdk.testapp.model.annotations.CityStateMarkerOptions;
import com.mapbox.mapboxsdk.testapp.utils.IconUtils;
/**
* Test activity showcasing using an InfoWindowAdapter to provide a custom InfoWindow content.
*/
public class InfoWindowAdapterActivity extends AppCompatActivity {
private MapView mapView;
private MapboxMap mapboxMap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_infowindow_adapter);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(map -> {
mapboxMap = map;
map.setStyle(Style.MAPBOX_STREETS, style -> {
addMarkers();
addCustomInfoWindowAdapter();
});
});
}
private void addMarkers() {
mapboxMap.addMarker(generateCityStateMarker("Andorra", 42.505777, 1.52529, "#F44336"));
mapboxMap.addMarker(generateCityStateMarker("Luxembourg", 49.815273, 6.129583, "#3F51B5"));
mapboxMap.addMarker(generateCityStateMarker("Monaco", 43.738418, 7.424616, "#673AB7"));
mapboxMap.addMarker(generateCityStateMarker("Vatican City", 41.902916, 12.453389, "#009688"));
mapboxMap.addMarker(generateCityStateMarker("San Marino", 43.942360, 12.457777, "#795548"));
mapboxMap.addMarker(generateCityStateMarker("Liechtenstein", 47.166000, 9.555373, "#FF5722"));
}
private CityStateMarkerOptions generateCityStateMarker(String title, double lat, double lng, String color) {
CityStateMarkerOptions marker = new CityStateMarkerOptions();
marker.title(title);
marker.position(new LatLng(lat, lng));
marker.infoWindowBackground(color);
Icon icon = IconUtils.drawableToIcon(this, R.drawable.ic_location_city, Color.parseColor(color));
marker.icon(icon);
return marker;
}
private void addCustomInfoWindowAdapter() {
mapboxMap.setInfoWindowAdapter(new MapboxMap.InfoWindowAdapter() {
private int tenDp = (int) getResources().getDimension(R.dimen.attr_margin);
@Override
public View getInfoWindow(@NonNull Marker marker) {
TextView textView = new TextView(InfoWindowAdapterActivity.this);
textView.setText(marker.getTitle());
textView.setTextColor(Color.WHITE);
if (marker instanceof CityStateMarker) {
CityStateMarker cityStateMarker = (CityStateMarker) marker;
textView.setBackgroundColor(Color.parseColor(cityStateMarker.getInfoWindowBackgroundColor()));
}
textView.setPadding(tenDp, tenDp, tenDp, tenDp);
return textView;
}
});
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}

View File

@@ -0,0 +1,140 @@
package com.mapbox.mapboxsdk.testapp.activity.location;
import android.annotation.SuppressLint;
import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;
import com.mapbox.android.core.permissions.PermissionsListener;
import com.mapbox.android.core.permissions.PermissionsManager;
import com.mapbox.mapboxsdk.location.LocationComponent;
import com.mapbox.mapboxsdk.location.LocationComponentActivationOptions;
import com.mapbox.mapboxsdk.location.LocationComponentOptions;
import com.mapbox.mapboxsdk.location.modes.CameraMode;
import com.mapbox.mapboxsdk.location.modes.RenderMode;
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.testapp.R;
import java.util.List;
public class LocationComponentActivationActivity extends AppCompatActivity implements OnMapReadyCallback {
private MapView mapView;
private MapboxMap mapboxMap;
private PermissionsManager permissionsManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_location_layer_activation_builder);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
if (PermissionsManager.areLocationPermissionsGranted(this)) {
mapView.getMapAsync(this);
} else {
permissionsManager = new PermissionsManager(new PermissionsListener() {
@Override
public void onExplanationNeeded(List<String> permissionsToExplain) {
Toast.makeText(LocationComponentActivationActivity.this, "You need to accept location permissions.",
Toast.LENGTH_SHORT).show();
}
@Override
public void onPermissionResult(boolean granted) {
if (granted) {
mapView.getMapAsync(LocationComponentActivationActivity.this);
} else {
finish();
}
}
});
permissionsManager.requestLocationPermissions(this);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
this.mapboxMap = mapboxMap;
mapboxMap.setStyle(Style.DARK,
style -> activateLocationComponent(style));
}
@SuppressLint("MissingPermission")
private void activateLocationComponent(@NonNull Style style) {
LocationComponent locationComponent = mapboxMap.getLocationComponent();
LocationComponentOptions locationComponentOptions = LocationComponentOptions.builder(this)
.elevation(5)
.accuracyAlpha(.6f)
.accuracyColor(Color.GREEN)
.foregroundDrawable(R.drawable.mapbox_logo_helmet)
.build();
LocationComponentActivationOptions locationComponentActivationOptions = LocationComponentActivationOptions
.builder(this, style)
.locationComponentOptions(locationComponentOptions)
.useDefaultLocationEngine(true)
.build();
locationComponent.activateLocationComponent(locationComponentActivationOptions);
locationComponent.setLocationComponentEnabled(true);
locationComponent.setRenderMode(RenderMode.NORMAL);
locationComponent.setCameraMode(CameraMode.TRACKING);
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}

View File

@@ -0,0 +1,176 @@
package com.mapbox.mapboxsdk.testapp.activity.location
import android.annotation.SuppressLint
import android.os.Bundle
import android.support.v4.app.Fragment
import android.support.v7.app.AppCompatActivity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import android.widget.Toast
import com.mapbox.android.core.location.LocationEngineCallback
import com.mapbox.android.core.location.LocationEngineResult
import com.mapbox.android.core.permissions.PermissionsListener
import com.mapbox.android.core.permissions.PermissionsManager
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory
import com.mapbox.mapboxsdk.geometry.LatLng
import com.mapbox.mapboxsdk.location.LocationComponentActivationOptions
import com.mapbox.mapboxsdk.maps.MapView
import com.mapbox.mapboxsdk.maps.MapboxMap
import com.mapbox.mapboxsdk.maps.Style
import com.mapbox.mapboxsdk.testapp.R
import kotlinx.android.synthetic.main.activity_location_layer_fragment.*
class LocationFragmentActivity : AppCompatActivity() {
private lateinit var permissionsManager: PermissionsManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_location_layer_fragment)
fab.setOnClickListener {
val fragment = supportFragmentManager.findFragmentByTag(EmptyFragment.TAG)
if (fragment == null) {
supportFragmentManager
.beginTransaction()
.replace(R.id.container, EmptyFragment.newInstance(), EmptyFragment.TAG)
.addToBackStack("transaction2")
.commit()
} else {
this.onBackPressed()
}
}
supportActionBar?.setDisplayHomeAsUpEnabled(true)
if (PermissionsManager.areLocationPermissionsGranted(this)) {
if (savedInstanceState == null) {
supportFragmentManager
.beginTransaction()
.replace(R.id.container, LocationFragment.newInstance(), LocationFragment.TAG)
.commit()
}
} else {
permissionsManager = PermissionsManager(object : PermissionsListener {
override fun onExplanationNeeded(permissionsToExplain: MutableList<String>?) {
Toast.makeText(this@LocationFragmentActivity, "You need to accept location permissions.",
Toast.LENGTH_SHORT).show()
}
override fun onPermissionResult(granted: Boolean) {
if (granted) {
if (savedInstanceState == null) {
supportFragmentManager
.beginTransaction()
.replace(R.id.container, LocationFragment.newInstance(), LocationFragment.TAG)
.commit()
}
} else {
finish()
}
}
})
permissionsManager.requestLocationPermissions(this)
}
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
class LocationFragment : Fragment(), LocationEngineCallback<LocationEngineResult> {
companion object {
const val TAG = "LFragment"
fun newInstance(): LocationFragment {
return LocationFragment()
}
}
private lateinit var mapView: MapView
private lateinit var mapboxMap: MapboxMap
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
mapView = MapView(inflater.context)
return mapView
}
@SuppressLint("MissingPermission")
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
mapView.onCreate(savedInstanceState)
mapView.getMapAsync {
mapboxMap = it
it.setStyle(Style.MAPBOX_STREETS) { style ->
val component = mapboxMap.locationComponent
component.activateLocationComponent(LocationComponentActivationOptions
.builder(activity!!, style)
.useDefaultLocationEngine(true)
.build())
component.isLocationComponentEnabled = true
component.locationEngine?.getLastLocation(this)
}
}
}
override fun onSuccess(result: LocationEngineResult?) {
mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(LatLng(result?.lastLocation), 12.0))
}
override fun onFailure(exception: Exception) {
// noop
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
mapView.onSaveInstanceState(outState)
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
override fun onDestroyView() {
super.onDestroyView()
mapView.onDestroy()
}
}
class EmptyFragment : Fragment() {
companion object {
const val TAG = "EmptyFragment"
fun newInstance(): EmptyFragment {
return EmptyFragment()
}
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val textView = TextView(inflater.context)
textView.text = "This is an empty Fragment"
return textView
}
}
}

View File

@@ -0,0 +1,142 @@
package com.mapbox.mapboxsdk.testapp.activity.location;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;
import com.mapbox.android.core.permissions.PermissionsListener;
import com.mapbox.android.core.permissions.PermissionsManager;
import com.mapbox.mapboxsdk.location.LocationComponent;
import com.mapbox.mapboxsdk.location.LocationComponentActivationOptions;
import com.mapbox.mapboxsdk.location.modes.RenderMode;
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.testapp.R;
import java.util.List;
public class LocationMapChangeActivity extends AppCompatActivity implements OnMapReadyCallback {
private MapView mapView;
private MapboxMap mapboxMap;
private PermissionsManager permissionsManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_location_layer_map_change);
mapView = findViewById(R.id.mapView);
FloatingActionButton stylesFab = findViewById(R.id.fabStyles);
stylesFab.setOnClickListener(v -> {
if (mapboxMap != null) {
mapboxMap.setStyle(new Style.Builder().fromUri(Utils.getNextStyle()));
}
});
mapView.onCreate(savedInstanceState);
if (PermissionsManager.areLocationPermissionsGranted(this)) {
mapView.getMapAsync(this);
} else {
permissionsManager = new PermissionsManager(new PermissionsListener() {
@Override
public void onExplanationNeeded(List<String> permissionsToExplain) {
Toast.makeText(LocationMapChangeActivity.this, "You need to accept location permissions.",
Toast.LENGTH_SHORT).show();
}
@Override
public void onPermissionResult(boolean granted) {
if (granted) {
mapView.getMapAsync(LocationMapChangeActivity.this);
} else {
finish();
}
}
});
permissionsManager.requestLocationPermissions(this);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
this.mapboxMap = mapboxMap;
mapboxMap.setStyle(new Style.Builder().fromUri(Utils.getNextStyle()),
style -> activateLocationComponent(style));
}
@SuppressLint("MissingPermission")
private void activateLocationComponent(@NonNull Style style) {
LocationComponent locationComponent = mapboxMap.getLocationComponent();
locationComponent.activateLocationComponent(
LocationComponentActivationOptions
.builder(this, style)
.useDefaultLocationEngine(true)
.build());
locationComponent.setLocationComponentEnabled(true);
locationComponent.setRenderMode(RenderMode.COMPASS);
locationComponent.addOnLocationClickListener(
() -> Toast.makeText(this, "Location clicked", Toast.LENGTH_SHORT).show());
locationComponent.addOnLocationLongClickListener(
() -> Toast.makeText(this, "Location long clicked", Toast.LENGTH_SHORT).show());
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}

View File

@@ -0,0 +1,432 @@
package com.mapbox.mapboxsdk.testapp.activity.location;
import android.annotation.SuppressLint;
import android.content.res.Configuration;
import android.location.Location;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.ListPopupWindow;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.Toast;
import com.mapbox.android.core.location.LocationEngineRequest;
import com.mapbox.android.core.permissions.PermissionsListener;
import com.mapbox.android.core.permissions.PermissionsManager;
import com.mapbox.mapboxsdk.location.LocationComponent;
import com.mapbox.mapboxsdk.location.LocationComponentActivationOptions;
import com.mapbox.mapboxsdk.location.LocationComponentOptions;
import com.mapbox.mapboxsdk.location.OnCameraTrackingChangedListener;
import com.mapbox.mapboxsdk.location.OnLocationCameraTransitionListener;
import com.mapbox.mapboxsdk.location.OnLocationClickListener;
import com.mapbox.mapboxsdk.location.modes.CameraMode;
import com.mapbox.mapboxsdk.location.modes.RenderMode;
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.testapp.R;
import java.util.ArrayList;
import java.util.List;
public class LocationModesActivity extends AppCompatActivity implements OnMapReadyCallback,
OnLocationClickListener, OnCameraTrackingChangedListener {
private MapView mapView;
private Button locationModeBtn;
private Button locationTrackingBtn;
private PermissionsManager permissionsManager;
private LocationComponent locationComponent;
private MapboxMap mapboxMap;
private boolean defaultStyle = false;
private static final String SAVED_STATE_CAMERA = "saved_state_camera";
private static final String SAVED_STATE_RENDER = "saved_state_render";
private static final String SAVED_STATE_LOCATION = "saved_state_location";
@CameraMode.Mode
private int cameraMode = CameraMode.TRACKING;
@RenderMode.Mode
private int renderMode = RenderMode.NORMAL;
private Location lastLocation;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_location_layer_mode);
mapView = findViewById(R.id.mapView);
locationModeBtn = findViewById(R.id.button_location_mode);
locationModeBtn.setOnClickListener(v -> {
if (locationComponent == null) {
return;
}
showModeListDialog();
});
locationTrackingBtn = findViewById(R.id.button_location_tracking);
locationTrackingBtn.setOnClickListener(v -> {
if (locationComponent == null) {
return;
}
showTrackingListDialog();
});
if (savedInstanceState != null) {
cameraMode = savedInstanceState.getInt(SAVED_STATE_CAMERA);
renderMode = savedInstanceState.getInt(SAVED_STATE_RENDER);
lastLocation = savedInstanceState.getParcelable(SAVED_STATE_LOCATION);
}
mapView.onCreate(savedInstanceState);
if (PermissionsManager.areLocationPermissionsGranted(this)) {
mapView.getMapAsync(this);
} else {
permissionsManager = new PermissionsManager(new PermissionsListener() {
@Override
public void onExplanationNeeded(List<String> permissionsToExplain) {
Toast.makeText(LocationModesActivity.this, "You need to accept location permissions.",
Toast.LENGTH_SHORT).show();
}
@Override
public void onPermissionResult(boolean granted) {
if (granted) {
mapView.getMapAsync(LocationModesActivity.this);
} else {
finish();
}
}
});
permissionsManager.requestLocationPermissions(this);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
@SuppressLint("MissingPermission")
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
this.mapboxMap = mapboxMap;
mapboxMap.setStyle(Style.MAPBOX_STREETS, style -> {
locationComponent = mapboxMap.getLocationComponent();
locationComponent.activateLocationComponent(
LocationComponentActivationOptions
.builder(this, style)
.useDefaultLocationEngine(true)
.locationEngineRequest(new LocationEngineRequest.Builder(750)
.setFastestInterval(750)
.setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY)
.build())
.build());
toggleStyle();
locationComponent.setLocationComponentEnabled(true);
locationComponent.addOnLocationClickListener(this);
locationComponent.addOnCameraTrackingChangedListener(this);
locationComponent.setCameraMode(cameraMode);
setRendererMode(renderMode);
locationComponent.forceLocationUpdate(lastLocation);
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_location_mode, menu);
return true;
}
@SuppressLint("MissingPermission")
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (locationComponent == null) {
return super.onOptionsItemSelected(item);
}
int id = item.getItemId();
if (id == R.id.action_style_change) {
toggleStyle();
return true;
} else if (id == R.id.action_map_style_change) {
toggleMapStyle();
return true;
} else if (id == R.id.action_component_disable) {
locationComponent.setLocationComponentEnabled(false);
return true;
} else if (id == R.id.action_component_enabled) {
locationComponent.setLocationComponentEnabled(true);
return true;
} else if (id == R.id.action_gestures_management_disabled) {
disableGesturesManagement();
return true;
} else if (id == R.id.action_gestures_management_enabled) {
enableGesturesManagement();
return true;
} else if (id == R.id.action_component_throttling_enabled) {
locationComponent.setMaxAnimationFps(5);
} else if (id == R.id.action_component_throttling_disabled) {
locationComponent.setMaxAnimationFps(Integer.MAX_VALUE);
} else if (id == R.id.action_component_animate_while_tracking) {
locationComponent.zoomWhileTracking(17, 750, new MapboxMap.CancelableCallback() {
@Override
public void onCancel() {
// No impl
}
@Override
public void onFinish() {
locationComponent.tiltWhileTracking(60);
}
});
if (locationComponent.getCameraMode() == CameraMode.NONE) {
Toast.makeText(this, "Not possible to animate - not tracking", Toast.LENGTH_SHORT).show();
}
}
return super.onOptionsItemSelected(item);
}
private void toggleStyle() {
if (locationComponent == null) {
return;
}
defaultStyle = !defaultStyle;
LocationComponentOptions options = LocationComponentOptions.createFromAttributes(
this, defaultStyle ? R.style.mapbox_LocationComponent : R.style.CustomLocationComponent);
if (defaultStyle) {
int[] padding;
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
padding = new int[] {0, 750, 0, 0};
} else {
padding = new int[] {0, 250, 0, 0};
}
options = options.toBuilder()
.padding(padding)
.build();
}
locationComponent.applyStyle(options);
}
private void toggleMapStyle() {
if (locationComponent == null) {
return;
}
String styleUrl = Style.DARK.equals(mapboxMap.getStyle().getUri()) ? Style.LIGHT : Style.DARK;
mapboxMap.setStyle(new Style.Builder().fromUri(styleUrl));
}
private void disableGesturesManagement() {
if (locationComponent == null) {
return;
}
LocationComponentOptions options = locationComponent
.getLocationComponentOptions()
.toBuilder()
.trackingGesturesManagement(false)
.build();
locationComponent.applyStyle(options);
}
private void enableGesturesManagement() {
if (locationComponent == null) {
return;
}
LocationComponentOptions options = locationComponent
.getLocationComponentOptions()
.toBuilder()
.trackingGesturesManagement(true)
.build();
locationComponent.applyStyle(options);
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@SuppressLint("MissingPermission")
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
outState.putInt(SAVED_STATE_CAMERA, cameraMode);
outState.putInt(SAVED_STATE_RENDER, renderMode);
if (locationComponent != null) {
outState.putParcelable(SAVED_STATE_LOCATION, locationComponent.getLastKnownLocation());
}
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
public void onLocationComponentClick() {
Toast.makeText(this, "OnLocationComponentClick", Toast.LENGTH_LONG).show();
}
private void showModeListDialog() {
List<String> modes = new ArrayList<>();
modes.add("Normal");
modes.add("Compass");
modes.add("GPS");
ArrayAdapter<String> profileAdapter = new ArrayAdapter<>(this,
android.R.layout.simple_list_item_1, modes);
ListPopupWindow listPopup = new ListPopupWindow(this);
listPopup.setAdapter(profileAdapter);
listPopup.setAnchorView(locationModeBtn);
listPopup.setOnItemClickListener((parent, itemView, position, id) -> {
String selectedMode = modes.get(position);
locationModeBtn.setText(selectedMode);
if (selectedMode.contentEquals("Normal")) {
setRendererMode(RenderMode.NORMAL);
} else if (selectedMode.contentEquals("Compass")) {
setRendererMode(RenderMode.COMPASS);
} else if (selectedMode.contentEquals("GPS")) {
setRendererMode(RenderMode.GPS);
}
listPopup.dismiss();
});
listPopup.show();
}
private void setRendererMode(@RenderMode.Mode int mode) {
renderMode = mode;
locationComponent.setRenderMode(mode);
if (mode == RenderMode.NORMAL) {
locationModeBtn.setText("Normal");
} else if (mode == RenderMode.COMPASS) {
locationModeBtn.setText("Compass");
} else if (mode == RenderMode.GPS) {
locationModeBtn.setText("Gps");
}
}
private void showTrackingListDialog() {
List<String> trackingTypes = new ArrayList<>();
trackingTypes.add("None");
trackingTypes.add("None Compass");
trackingTypes.add("None GPS");
trackingTypes.add("Tracking");
trackingTypes.add("Tracking Compass");
trackingTypes.add("Tracking GPS");
trackingTypes.add("Tracking GPS North");
ArrayAdapter<String> profileAdapter = new ArrayAdapter<>(this,
android.R.layout.simple_list_item_1, trackingTypes);
ListPopupWindow listPopup = new ListPopupWindow(this);
listPopup.setAdapter(profileAdapter);
listPopup.setAnchorView(locationTrackingBtn);
listPopup.setOnItemClickListener((parent, itemView, position, id) -> {
String selectedTrackingType = trackingTypes.get(position);
locationTrackingBtn.setText(selectedTrackingType);
if (selectedTrackingType.contentEquals("None")) {
setCameraTrackingMode(CameraMode.NONE);
} else if (selectedTrackingType.contentEquals("None Compass")) {
setCameraTrackingMode(CameraMode.NONE_COMPASS);
} else if (selectedTrackingType.contentEquals("None GPS")) {
setCameraTrackingMode(CameraMode.NONE_GPS);
} else if (selectedTrackingType.contentEquals("Tracking")) {
setCameraTrackingMode(CameraMode.TRACKING);
} else if (selectedTrackingType.contentEquals("Tracking Compass")) {
setCameraTrackingMode(CameraMode.TRACKING_COMPASS);
} else if (selectedTrackingType.contentEquals("Tracking GPS")) {
setCameraTrackingMode(CameraMode.TRACKING_GPS);
} else if (selectedTrackingType.contentEquals("Tracking GPS North")) {
setCameraTrackingMode(CameraMode.TRACKING_GPS_NORTH);
}
listPopup.dismiss();
});
listPopup.show();
}
private void setCameraTrackingMode(@CameraMode.Mode int mode) {
locationComponent.setCameraMode(mode, 1200, 16.0, null, 45.0,
new OnLocationCameraTransitionListener() {
@Override
public void onLocationCameraTransitionFinished(@CameraMode.Mode int cameraMode) {
Toast.makeText(LocationModesActivity.this, "Transition finished", Toast.LENGTH_SHORT).show();
}
@Override
public void onLocationCameraTransitionCanceled(@CameraMode.Mode int cameraMode) {
Toast.makeText(LocationModesActivity.this, "Transition canceled", Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void onCameraTrackingDismissed() {
locationTrackingBtn.setText("None");
}
@Override
public void onCameraTrackingChanged(int currentMode) {
this.cameraMode = currentMode;
if (currentMode == CameraMode.NONE) {
locationTrackingBtn.setText("None");
} else if (currentMode == CameraMode.NONE_COMPASS) {
locationTrackingBtn.setText("None Compass");
} else if (currentMode == CameraMode.NONE_GPS) {
locationTrackingBtn.setText("None GPS");
} else if (currentMode == CameraMode.TRACKING) {
locationTrackingBtn.setText("Tracking");
} else if (currentMode == CameraMode.TRACKING_COMPASS) {
locationTrackingBtn.setText("Tracking Compass");
} else if (currentMode == CameraMode.TRACKING_GPS) {
locationTrackingBtn.setText("Tracking GPS");
} else if (currentMode == CameraMode.TRACKING_GPS_NORTH) {
locationTrackingBtn.setText("Tracking GPS North");
}
}
}

View File

@@ -0,0 +1,170 @@
package com.mapbox.mapboxsdk.testapp.activity.location;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;
import com.mapbox.android.core.location.LocationEngine;
import com.mapbox.android.core.location.LocationEngineProvider;
import com.mapbox.android.core.location.LocationEngineRequest;
import com.mapbox.android.core.permissions.PermissionsListener;
import com.mapbox.android.core.permissions.PermissionsManager;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.location.LocationComponent;
import com.mapbox.mapboxsdk.location.LocationComponentActivationOptions;
import com.mapbox.mapboxsdk.location.modes.RenderMode;
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.testapp.R;
import java.util.List;
public class ManualLocationUpdatesActivity extends AppCompatActivity implements OnMapReadyCallback {
private MapView mapView;
private LocationComponent locationComponent;
private LocationEngine locationEngine;
private PermissionsManager permissionsManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_location_manual_update);
locationEngine = LocationEngineProvider.getBestLocationEngine(this, false);
FloatingActionButton fabManualUpdate = findViewById(R.id.fabManualLocationChange);
fabManualUpdate.setOnClickListener(v -> {
if (locationComponent != null && locationComponent.getLocationEngine() == null) {
locationComponent.forceLocationUpdate(
Utils.getRandomLocation(LatLngBounds.from(60, 25, 40, -5)));
}
});
fabManualUpdate.setEnabled(false);
FloatingActionButton fabToggle = findViewById(R.id.fabToggleManualLocation);
fabToggle.setOnClickListener(v -> {
if (locationComponent != null) {
locationComponent.setLocationEngine(locationComponent.getLocationEngine() == null ? locationEngine : null);
if (locationComponent.getLocationEngine() == null) {
fabToggle.setImageResource(R.drawable.ic_layers_clear);
fabManualUpdate.setEnabled(true);
fabManualUpdate.setAlpha(1f);
Toast.makeText(
ManualLocationUpdatesActivity.this.getApplicationContext(),
"LocationEngine disabled, use manual updates",
Toast.LENGTH_SHORT).show();
} else {
fabToggle.setImageResource(R.drawable.ic_layers);
fabManualUpdate.setEnabled(false);
fabManualUpdate.setAlpha(0.5f);
Toast.makeText(
ManualLocationUpdatesActivity.this.getApplicationContext(),
"LocationEngine enabled",
Toast.LENGTH_SHORT).show();
}
}
});
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
if (PermissionsManager.areLocationPermissionsGranted(this)) {
mapView.getMapAsync(this);
} else {
permissionsManager = new PermissionsManager(new PermissionsListener() {
@Override
public void onExplanationNeeded(List<String> permissionsToExplain) {
Toast.makeText(ManualLocationUpdatesActivity.this.getApplicationContext(),
"You need to accept location permissions.",
Toast.LENGTH_SHORT
).show();
}
@Override
public void onPermissionResult(boolean granted) {
if (granted) {
mapView.getMapAsync(ManualLocationUpdatesActivity.this);
} else {
finish();
}
}
});
permissionsManager.requestLocationPermissions(this);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
permissionsManager.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
@SuppressLint("MissingPermission")
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
mapboxMap.setStyle(new Style.Builder().fromUri(Style.MAPBOX_STREETS), style -> {
locationComponent = mapboxMap.getLocationComponent();
locationComponent.activateLocationComponent(
LocationComponentActivationOptions
.builder(this, style)
.locationEngine(locationEngine)
.locationEngineRequest(new LocationEngineRequest.Builder(500)
.setFastestInterval(500)
.setPriority(LocationEngineRequest.PRIORITY_HIGH_ACCURACY).build())
.build());
locationComponent.setLocationComponentEnabled(true);
locationComponent.setRenderMode(RenderMode.COMPASS);
});
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}

View File

@@ -0,0 +1,59 @@
package com.mapbox.mapboxsdk.testapp.activity.location;
import android.location.Location;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import java.util.Random;
import timber.log.Timber;
/**
* Useful utilities used throughout the testapp.
*/
public class Utils {
private static final String[] STYLES = new String[] {
Style.MAPBOX_STREETS,
Style.OUTDOORS,
Style.LIGHT,
Style.DARK,
Style.SATELLITE_STREETS
};
private static int index;
/**
* Utility to cycle through map styles. Useful to test if runtime styling source and layers transfer over to new
* style.
*
* @return a string ID representing the map style
*/
public static String getNextStyle() {
index++;
if (index == STYLES.length) {
index = 0;
}
return STYLES[index];
}
/**
* Utility for getting a random coordinate inside a provided bounds and creates a {@link Location} from it.
*
* @param bounds bounds of the generated location
* @return a {@link Location} object using the random coordinate
*/
public static Location getRandomLocation(LatLngBounds bounds) {
Random random = new Random();
double randomLat = bounds.getLatSouth() + (bounds.getLatNorth() - bounds.getLatSouth()) * random.nextDouble();
double randomLon = bounds.getLonWest() + (bounds.getLonEast() - bounds.getLonWest()) * random.nextDouble();
Location location = new Location("random-loc");
location.setLongitude(randomLon);
location.setLatitude(randomLat);
Timber.d("getRandomLatLng: %s", location.toString());
return location;
}
}

View File

@@ -0,0 +1,282 @@
package com.mapbox.mapboxsdk.testapp.activity.maplayout;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.BottomSheetBehavior;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
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.MapboxMapOptions;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.utils.MapFragmentUtils;
/**
* Test activity showcasing using a bottomView with a MapView and stacking map fragments below.
*/
public class BottomSheetActivity extends AppCompatActivity {
private static final String TAG_MAIN_FRAGMENT = "com.mapbox.mapboxsdk.fragment.tag.main";
private static final String TAG_BOTTOM_FRAGMENT = "com.mapbox.mapboxsdk.fragment.tag.bottom";
private static final String AMOUNT_OF_MAIN_MAP_FRAGMENTS = "Amount of main map fragments: %s";
private boolean bottomSheetFragmentAdded;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bottom_sheet);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
findViewById(R.id.fabFragment).setOnClickListener(v -> addMapFragment());
findViewById(R.id.fabBottomSheet).setOnClickListener(v -> toggleBottomSheetMapFragment());
BottomSheetBehavior bottomSheetBehavior = BottomSheetBehavior.from(findViewById(R.id.bottom_sheet));
bottomSheetBehavior.setPeekHeight((int) (64 * getResources().getDisplayMetrics().density));
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
toggleBottomSheetMapFragment();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
onBackPressed();
}
return super.onOptionsItemSelected(item);
}
@Override
public void onBackPressed() {
FragmentManager fragmentManager = getSupportFragmentManager();
if (fragmentManager.getBackStackEntryCount() > 0) {
fragmentManager.popBackStack();
} else {
super.onBackPressed();
}
}
private void addMapFragment() {
FragmentManager fragmentManager = getSupportFragmentManager();
int fragmentCount = fragmentManager.getBackStackEntryCount();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
MainMapFragment mainMapFragment = MainMapFragment.newInstance(this, fragmentCount);
if (fragmentCount == 0) {
fragmentTransaction.add(R.id.fragment_container, mainMapFragment, TAG_MAIN_FRAGMENT);
} else {
fragmentTransaction.replace(R.id.fragment_container, mainMapFragment, TAG_MAIN_FRAGMENT);
}
fragmentTransaction.addToBackStack(String.valueOf(mainMapFragment.hashCode()));
fragmentTransaction.commit();
Toast.makeText(getApplicationContext(),
String.format(AMOUNT_OF_MAIN_MAP_FRAGMENTS, (fragmentCount + 1)),
Toast.LENGTH_SHORT
).show();
}
private void toggleBottomSheetMapFragment() {
if (!bottomSheetFragmentAdded) {
addBottomSheetMapFragment();
} else {
removeBottomSheetFragment();
}
bottomSheetFragmentAdded = !bottomSheetFragmentAdded;
}
private void addBottomSheetMapFragment() {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.add(R.id.fragment_container_bottom, BottomSheetFragment.newInstance(this), TAG_BOTTOM_FRAGMENT);
fragmentTransaction.commit();
}
private void removeBottomSheetFragment() {
Fragment fragment = getSupportFragmentManager().findFragmentByTag(TAG_BOTTOM_FRAGMENT);
if (fragment != null) {
getSupportFragmentManager().beginTransaction().remove(fragment).commit();
}
}
public static class MainMapFragment extends Fragment implements OnMapReadyCallback {
private static final String[] STYLES = new String[] {
Style.MAPBOX_STREETS,
Style.SATELLITE_STREETS,
Style.LIGHT,
Style.DARK,
Style.SATELLITE,
Style.OUTDOORS
};
private MapView map;
public static MainMapFragment newInstance(Context context, int mapCounter) {
MainMapFragment mapFragment = new MainMapFragment();
Bundle bundle = new Bundle();
bundle.putInt("mapcounter", mapCounter);
mapFragment.setArguments(bundle);
MapboxMapOptions mapboxMapOptions = MapboxMapOptions.createFromAttributes(context);
mapFragment.setArguments(MapFragmentUtils.createFragmentArgs(mapboxMapOptions));
return mapFragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
Context context = inflater.getContext();
return map = new MapView(context, MapFragmentUtils.resolveArgs(context, getArguments()));
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
map.onCreate(savedInstanceState);
map.getMapAsync(this);
}
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(37.760545, -122.436055), 15));
mapboxMap.setStyle(
new Style.Builder().fromUri(
STYLES[Math.min(Math.max(getArguments().getInt("mapcounter"), 0), STYLES.length - 1)]
)
);
}
@Override
public void onStart() {
super.onStart();
map.onStart();
}
@Override
public void onResume() {
super.onResume();
map.onResume();
}
@Override
public void onPause() {
super.onPause();
map.onPause();
}
@Override
public void onStop() {
super.onStop();
map.onStop();
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
map.onSaveInstanceState(outState);
}
@Override
public void onLowMemory() {
super.onLowMemory();
map.onLowMemory();
}
@Override
public void onDestroyView() {
super.onDestroyView();
map.onDestroy();
}
}
public static class BottomSheetFragment extends Fragment implements OnMapReadyCallback {
private MapView map;
public static BottomSheetFragment newInstance(Context context) {
BottomSheetFragment mapFragment = new BottomSheetFragment();
MapboxMapOptions mapboxMapOptions = MapboxMapOptions.createFromAttributes(context);
mapboxMapOptions.renderSurfaceOnTop(true);
mapFragment.setArguments(MapFragmentUtils.createFragmentArgs(mapboxMapOptions));
return mapFragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
Context context = inflater.getContext();
return map = new MapView(context, MapFragmentUtils.resolveArgs(context, getArguments()));
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
map.onCreate(savedInstanceState);
map.getMapAsync(this);
}
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(37.760545, -122.436055), 15));
mapboxMap.setStyle(Style.LIGHT);
}
@Override
public void onStart() {
super.onStart();
map.onStart();
}
@Override
public void onResume() {
super.onResume();
map.onResume();
}
@Override
public void onPause() {
super.onPause();
map.onPause();
}
@Override
public void onStop() {
super.onStop();
map.onStop();
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
map.onSaveInstanceState(outState);
}
@Override
public void onLowMemory() {
super.onLowMemory();
map.onLowMemory();
}
@Override
public void onDestroyView() {
super.onDestroyView();
map.onDestroy();
}
}
}

View File

@@ -0,0 +1,306 @@
package com.mapbox.mapboxsdk.testapp.activity.maplayout;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.style.layers.Layer;
import com.mapbox.mapboxsdk.style.layers.Property;
import com.mapbox.mapboxsdk.testapp.R;
import java.util.List;
import java.util.Locale;
import timber.log.Timber;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility;
/**
* Test activity showcasing the different debug modes and allows to cycle between the default map styles.
*/
public class DebugModeActivity extends AppCompatActivity implements OnMapReadyCallback, MapboxMap.OnFpsChangedListener {
private MapView mapView;
private MapboxMap mapboxMap;
private MapboxMap.OnCameraMoveListener cameraMoveListener;
private ActionBarDrawerToggle actionBarDrawerToggle;
private int currentStyleIndex;
private boolean isReportFps = true;
private static final String[] STYLES = new String[] {
Style.MAPBOX_STREETS,
Style.OUTDOORS,
Style.LIGHT,
Style.DARK,
Style.SATELLITE,
Style.SATELLITE_STREETS,
Style.TRAFFIC_DAY,
Style.TRAFFIC_NIGHT
};
private TextView fpsView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_debug_mode);
setupToolbar();
setupMapView(savedInstanceState);
setupDebugChangeView();
setupStyleChangeView();
}
private void setupToolbar() {
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
DrawerLayout drawerLayout = findViewById(R.id.drawer_layout);
actionBarDrawerToggle = new ActionBarDrawerToggle(this,
drawerLayout,
R.string.navigation_drawer_open,
R.string.navigation_drawer_close
);
actionBarDrawerToggle.setDrawerIndicatorEnabled(true);
actionBarDrawerToggle.syncState();
}
}
private void setupMapView(Bundle savedInstanceState) {
MapboxMapOptions mapboxMapOptions = setupMapboxMapOptions();
mapView = new MapView(this, mapboxMapOptions);
((ViewGroup) findViewById(R.id.coordinator_layout)).addView(mapView, 0);
mapView.addOnDidFinishLoadingStyleListener(() -> {
if (mapboxMap != null) {
setupNavigationView(mapboxMap.getStyle().getLayers());
}
});
mapView.setTag(true);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
mapView.addOnDidFinishLoadingStyleListener(() -> Timber.d("Style loaded"));
}
protected MapboxMapOptions setupMapboxMapOptions() {
return MapboxMapOptions.createFromAttributes(this, null);
}
@Override
public void onMapReady(@NonNull MapboxMap map) {
mapboxMap = map;
mapboxMap.setStyle(
new Style.Builder().fromUri(STYLES[currentStyleIndex]), style -> setupNavigationView(style.getLayers())
);
setupZoomView();
setFpsView();
}
private void setFpsView() {
fpsView = findViewById(R.id.fpsView);
mapboxMap.setOnFpsChangedListener(this);
}
@Override
public void onFpsChanged(double fps) {
fpsView.setText(String.format(Locale.US, "FPS: %4.2f", fps));
}
private void setupNavigationView(List<Layer> layerList) {
Timber.v("New style loaded with JSON: %s", mapboxMap.getStyle().getJson());
final LayerListAdapter adapter = new LayerListAdapter(this, layerList);
ListView listView = findViewById(R.id.listView);
listView.setAdapter(adapter);
listView.setOnItemClickListener((parent, view, position, id) -> {
Layer clickedLayer = adapter.getItem(position);
toggleLayerVisibility(clickedLayer);
closeNavigationView();
});
}
private void toggleLayerVisibility(Layer layer) {
boolean isVisible = layer.getVisibility().getValue().equals(Property.VISIBLE);
layer.setProperties(
visibility(
isVisible ? Property.NONE : Property.VISIBLE
)
);
}
private void closeNavigationView() {
DrawerLayout drawerLayout = findViewById(R.id.drawer_layout);
drawerLayout.closeDrawers();
}
private void setupZoomView() {
final TextView textView = findViewById(R.id.textZoom);
mapboxMap.addOnCameraMoveListener(cameraMoveListener = new MapboxMap.OnCameraMoveListener() {
@Override
public void onCameraMove() {
textView.setText(String.format(DebugModeActivity.this.getString(
R.string.debug_zoom), mapboxMap.getCameraPosition().zoom));
}
});
}
private void setupDebugChangeView() {
FloatingActionButton fabDebug = findViewById(R.id.fabDebug);
fabDebug.setOnClickListener(view -> {
if (mapboxMap != null) {
Timber.d("Debug FAB: isDebug Active? %s", mapboxMap.isDebugActive());
mapboxMap.cycleDebugOptions();
}
});
}
private void setupStyleChangeView() {
FloatingActionButton fabStyles = findViewById(R.id.fabStyles);
fabStyles.setOnClickListener(view -> {
if (mapboxMap != null) {
currentStyleIndex++;
if (currentStyleIndex == STYLES.length) {
currentStyleIndex = 0;
}
mapboxMap.setStyle(new Style.Builder().fromUri(STYLES[currentStyleIndex]));
}
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId();
if (itemId == R.id.menu_action_toggle_report_fps) {
isReportFps = !isReportFps;
fpsView.setVisibility(isReportFps ? View.VISIBLE : View.GONE);
mapboxMap.setOnFpsChangedListener(isReportFps ? this : null);
} else if (itemId == R.id.menu_action_limit_to_30_fps) {
mapView.setMaximumFps(30);
} else if (itemId == R.id.menu_action_limit_to_60_fps) {
mapView.setMaximumFps(60);
}
return actionBarDrawerToggle.onOptionsItemSelected(item) || super.onOptionsItemSelected(item);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_debug, menu);
return true;
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mapboxMap != null) {
mapboxMap.removeOnCameraMoveListener(cameraMoveListener);
}
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
private static class LayerListAdapter extends BaseAdapter {
private LayoutInflater layoutInflater;
private List<Layer> layers;
LayerListAdapter(Context context, List<Layer> layers) {
this.layoutInflater = LayoutInflater.from(context);
this.layers = layers;
}
@Override
public int getCount() {
return layers.size();
}
@Override
public Layer getItem(int position) {
return layers.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Layer layer = layers.get(position);
View view = convertView;
if (view == null) {
view = layoutInflater.inflate(android.R.layout.simple_list_item_2, parent, false);
ViewHolder holder = new ViewHolder(
view.findViewById(android.R.id.text1),
view.findViewById(android.R.id.text2)
);
view.setTag(holder);
}
ViewHolder holder = (ViewHolder) view.getTag();
holder.text.setText(layer.getClass().getSimpleName());
holder.subText.setText(layer.getId());
return view;
}
private static class ViewHolder {
final TextView text;
final TextView subText;
ViewHolder(TextView text, TextView subText) {
this.text = text;
this.subText = subText;
}
}
}
}

View File

@@ -0,0 +1,160 @@
package com.mapbox.mapboxsdk.testapp.activity.maplayout;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
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.MapboxMapOptions;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.maps.UiSettings;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.utils.MapFragmentUtils;
/**
* Test activity showcasing having 2 maps on top of each other.
* <p>
* The small map is using the `mapbox_enableZMediaOverlay="true"` configuration
* </p>
*/
public class DoubleMapActivity extends AppCompatActivity {
private static final String TAG_FRAGMENT = "map";
private static final LatLng MACHU_PICCHU = new LatLng(-13.1650709, -72.5447154);
private static final double ZOOM_IN = 12;
private static final double ZOOM_OUT = 4;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_fragment);
if (savedInstanceState == null) {
MapboxMapOptions options = MapboxMapOptions.createFromAttributes(this, null);
options.camera(new CameraPosition.Builder()
.target(MACHU_PICCHU)
.zoom(ZOOM_IN)
.build()
);
DoubleMapFragment doubleMapFragment = new DoubleMapFragment();
doubleMapFragment.setArguments(MapFragmentUtils.createFragmentArgs(options));
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.add(R.id.fragment_container, doubleMapFragment, TAG_FRAGMENT);
transaction.commit();
}
}
/**
* Custom fragment containing 2 MapViews.
*/
public static class DoubleMapFragment extends Fragment {
private MapView mapView;
private MapView mapViewMini;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_double_map, container, false);
}
@Override
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// MapView large
mapView = new MapView(view.getContext(), MapFragmentUtils.resolveArgs(view.getContext(), getArguments()));
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(mapboxMap -> mapboxMap.setStyle(Style.MAPBOX_STREETS));
((ViewGroup) view.findViewById(R.id.container)).addView(mapView, 0);
// MapView mini
mapViewMini = view.findViewById(R.id.mini_map);
mapViewMini.onCreate(savedInstanceState);
mapViewMini.getMapAsync(mapboxMap -> {
mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(
new CameraPosition.Builder().target(MACHU_PICCHU)
.zoom(ZOOM_OUT)
.build()
)
);
mapboxMap.setStyle(new Style.Builder().fromUri(Style.LIGHT));
UiSettings uiSettings = mapboxMap.getUiSettings();
uiSettings.setAllGesturesEnabled(false);
uiSettings.setCompassEnabled(false);
uiSettings.setAttributionEnabled(false);
uiSettings.setLogoEnabled(false);
mapboxMap.addOnMapClickListener(point -> {
// test if we can open 2 activities after each other
Toast.makeText(mapViewMini.getContext(), "Creating a new Activity instance", Toast.LENGTH_SHORT).show();
startActivity(new Intent(mapViewMini.getContext(), DoubleMapActivity.class));
return false;
});
});
}
@Override
public void onResume() {
super.onResume();
mapView.onResume();
mapViewMini.onResume();
}
@Override
public void onStart() {
super.onStart();
mapView.onStart();
mapViewMini.onStart();
}
@Override
public void onPause() {
super.onPause();
mapView.onPause();
mapViewMini.onPause();
}
@Override
public void onStop() {
super.onStop();
mapView.onStop();
mapViewMini.onStop();
}
@Override
public void onDestroyView() {
super.onDestroyView();
mapView.onDestroy();
mapViewMini.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
mapViewMini.onLowMemory();
}
@Override
public void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
// Mini map view is not interactive in this case, so we shouldn't save the instance.
// If we'd like to support state saving for both maps, they'd have to be kept in separate fragments.
//mapViewMini.onSaveInstanceState(outState);
}
}
}

View File

@@ -0,0 +1,154 @@
package com.mapbox.mapboxsdk.testapp.activity.maplayout
import android.annotation.SuppressLint
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.TextView
import com.mapbox.mapboxsdk.maps.MapView
import com.mapbox.mapboxsdk.maps.Style
import com.mapbox.mapboxsdk.testapp.R
import kotlinx.android.synthetic.main.activity_recyclerview.*
/**
* TestActivity showcasing how to integrate multiple GLSurfaceView MapViews in a RecyclerView.
* <p>
* It requires calling the correct lifecycle methods when detaching and attaching the View to
* the RecyclerView with onViewAttachedToWindow and onViewDetachedFromWindow.
* </p>
*/
@SuppressLint("ClickableViewAccessibility")
open class GLSurfaceRecyclerViewActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_recyclerview)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.adapter = ItemAdapter(this, LayoutInflater.from(this))
}
override fun onLowMemory() {
super.onLowMemory()
// to release memory, we need to call MapView#onLowMemory
(recyclerView.adapter as ItemAdapter).onLowMemory()
}
override fun onDestroy() {
super.onDestroy()
// to perform cleanup, we need to call MapView#onDestroy
(recyclerView.adapter as ItemAdapter).onDestroy()
}
open fun getMapItemLayoutId(): Int {
return R.layout.item_map_gl
}
class ItemAdapter(private val activity: GLSurfaceRecyclerViewActivity, private val inflater: LayoutInflater) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private val items = listOf(
"one", "two", "three", MapItem(Style.MAPBOX_STREETS), "four", "five", MapItem(Style.DARK), "seven", "eight", "nine", "ten",
"eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen",
"nineteen", "twenty", "twenty-one"
)
private var mapHolders: MutableList<MapHolder> = mutableListOf()
companion object {
const val TYPE_MAP = 0
const val TYPE_TEXT = 1
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return if (viewType == TYPE_MAP) {
val mapView = inflater.inflate(activity.getMapItemLayoutId(), parent, false) as MapView
val mapHolder = MapHolder(mapView)
mapHolders.add(mapHolder)
return mapHolder
} else {
TextHolder(inflater.inflate(android.R.layout.simple_list_item_1, parent, false) as TextView)
}
}
override fun onViewAttachedToWindow(holder: RecyclerView.ViewHolder) {
super.onViewAttachedToWindow(holder)
if (holder is MapHolder) {
val mapView = holder.mapView
mapView.onStart()
mapView.onResume()
}
}
override fun onViewDetachedFromWindow(holder: RecyclerView.ViewHolder) {
super.onViewDetachedFromWindow(holder)
if (holder is MapHolder) {
val mapView = holder.mapView
mapView.onPause()
mapView.onStop()
}
}
override fun getItemCount(): Int {
return items.count()
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is TextHolder) {
holder.bind(items[position] as String)
} else if (holder is MapHolder) {
holder.bind(items[position] as MapItem)
}
}
override fun getItemViewType(position: Int): Int {
return if (items[position] is MapItem) {
TYPE_MAP
} else {
TYPE_TEXT
}
}
fun onLowMemory() {
for (mapHolder in mapHolders) {
mapHolder.mapView.onLowMemory()
}
}
fun onDestroy() {
for (mapHolder in mapHolders) {
mapHolder.mapView.let {
it.onPause()
it.onStop()
it.onDestroy()
}
}
}
data class MapItem(val style: String)
class MapHolder(val mapView: MapView) : RecyclerView.ViewHolder(mapView) {
init {
// unfortunately, if there are multiple maps hosted in one activity, state saving is not possible
mapView.onCreate(null)
mapView.setOnTouchListener { view, motionEvent ->
// Disallow the touch request for recyclerView scroll
view.parent.requestDisallowInterceptTouchEvent(true)
mapView.onTouchEvent(motionEvent)
true
}
}
fun bind(mapItem: MapItem) {
mapView.getMapAsync { mapboxMap -> mapboxMap.setStyle(mapItem.style) }
}
}
class TextHolder(val textView: TextView) : RecyclerView.ViewHolder(textView) {
fun bind(item: String) {
textView.text = item
}
}
}
}

View File

@@ -0,0 +1,154 @@
package com.mapbox.mapboxsdk.testapp.activity.maplayout;
import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.Gravity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.FrameLayout;
import com.mapbox.mapboxsdk.annotations.PolygonOptions;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
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.testapp.R;
/**
* Test activity showcasing restricting user gestures to a bounds around Iceland, almost worldview and IDL.
*/
public class LatLngBoundsForCameraActivity extends AppCompatActivity implements OnMapReadyCallback {
private static final LatLngBounds ICELAND_BOUNDS = new LatLngBounds.Builder()
.include(new LatLng(66.852863, -25.985652))
.include(new LatLng(62.985661, -12.626277))
.build();
private static final LatLngBounds ALMOST_WORLD_BOUNDS = new LatLngBounds.Builder()
.include(new LatLng(20.0, 170.0))
.include(new LatLng(-20, -170.0))
.build();
private static final LatLngBounds CROSS_IDL_BOUNDS = new LatLngBounds.Builder()
.include(new LatLng(20.0, 170.0))
.include(new LatLng(-20, 190.0))
.build();
private MapView mapView;
private MapboxMap mapboxMap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_restricted_bounds);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
}
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
this.mapboxMap = mapboxMap;
mapboxMap.setStyle(Style.SATELLITE_STREETS);
mapboxMap.setMinZoomPreference(2);
mapboxMap.getUiSettings().setFlingVelocityAnimationEnabled(false);
showCrosshair();
setupBounds(ICELAND_BOUNDS);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_bounds, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_action_allmost_world_bounds:
setupBounds(ALMOST_WORLD_BOUNDS);
return true;
case R.id.menu_action_cross_idl:
setupBounds(CROSS_IDL_BOUNDS);
return true;
case R.id.menu_action_reset:
setupBounds(null);
return true;
}
return super.onOptionsItemSelected(item);
}
private void setupBounds(@Nullable LatLngBounds bounds) {
mapboxMap.setLatLngBoundsForCameraTarget(bounds);
showBoundsArea(bounds);
}
private void showBoundsArea(@Nullable LatLngBounds bounds) {
mapboxMap.clear();
if (bounds != null) {
PolygonOptions boundsArea = new PolygonOptions()
.add(bounds.getNorthWest())
.add(bounds.getNorthEast())
.add(bounds.getSouthEast())
.add(bounds.getSouthWest());
boundsArea.alpha(0.25f);
boundsArea.fillColor(Color.RED);
mapboxMap.addPolygon(boundsArea);
}
}
private void showCrosshair() {
View crosshair = new View(this);
crosshair.setLayoutParams(new FrameLayout.LayoutParams(10, 10, Gravity.CENTER));
crosshair.setBackgroundColor(Color.BLUE);
mapView.addView(crosshair);
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}

View File

@@ -0,0 +1,80 @@
package com.mapbox.mapboxsdk.testapp.activity.maplayout;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
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.Style;
import com.mapbox.mapboxsdk.testapp.R;
/**
* Test activity that displays the city of Suzhou with a mixture of server-generated
* latin glyphs and CJK glyphs generated locally using "Droid Sans" as a font family.
*/
public class LocalGlyphActivity extends AppCompatActivity {
private MapView mapView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_local_glyph);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(mapboxMap -> {
mapboxMap.setStyle(Style.MAPBOX_STREETS);
// Set initial position to Suzhou
mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(
new CameraPosition.Builder()
.target(new LatLng(31.3003, 120.7457))
.zoom(11)
.bearing(0)
.tilt(0)
.build()));
});
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
}

View File

@@ -0,0 +1,89 @@
package com.mapbox.mapboxsdk.testapp.activity.maplayout;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.testapp.R;
import timber.log.Timber;
/**
* Test activity showcasing how to listen to map change events.
*/
public class MapChangeActivity extends AppCompatActivity {
private MapView mapView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_simple);
mapView = findViewById(R.id.mapView);
mapView.addOnCameraIsChangingListener(() -> Timber.v("OnCameraIsChanging"));
mapView.addOnCameraDidChangeListener(animated -> Timber.v("OnCamaraDidChange: animated: %s", animated));
mapView.addOnCameraWillChangeListener(animated -> Timber.v("OnCameraWilChange: animated: %s", animated));
mapView.addOnDidFailLoadingMapListener(errorMessage -> Timber.v("OnDidFailLoadingMap: %s", errorMessage));
mapView.addOnDidFinishLoadingMapListener(() -> Timber.v("OnDidFinishLoadingMap"));
mapView.addOnDidFinishLoadingStyleListener(() -> Timber.v("OnDidFinishLoadingStyle"));
mapView.addOnDidFinishRenderingFrameListener(fully -> Timber.v("OnDidFinishRenderingFrame: fully: %s", fully));
mapView.addOnDidFinishRenderingMapListener(fully -> Timber.v("OnDidFinishRenderingMap: fully: %s", fully));
mapView.addOnDidBecomeIdleListener(() -> Timber.v("OnDidBecomeIdle"));
mapView.addOnSourceChangedListener(sourceId -> Timber.v("OnSourceChangedListener: source with id: %s", sourceId));
mapView.addOnWillStartLoadingMapListener(() -> Timber.v("OnWillStartLoadingMap"));
mapView.addOnWillStartRenderingFrameListener(() -> Timber.v("OnWillStartRenderingFrame"));
mapView.addOnWillStartRenderingMapListener(() -> Timber.v("OnWillStartRenderingMap"));
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(mapboxMap -> {
mapboxMap.setStyle(Style.MAPBOX_STREETS);
mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(
new LatLng(55.754020, 37.620948), 12), 9000);
});
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
}

View File

@@ -0,0 +1,110 @@
package com.mapbox.mapboxsdk.testapp.activity.maplayout;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.testapp.R;
/**
* Test activity showcasing showing a Map inside of a DialogFragment.
*/
public class MapInDialogActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_in_dialog);
Button button = findViewById(R.id.button_open_dialog);
button.setOnClickListener(view -> {
FragmentManager fm = getSupportFragmentManager();
MapDialogFragment editNameDialogFragment = MapDialogFragment.newInstance("Map Dialog");
editNameDialogFragment.show(fm, "fragment_dialog_map");
});
}
public static class MapDialogFragment extends DialogFragment {
private MapView mapView;
public MapDialogFragment() {
}
public static MapDialogFragment newInstance(String title) {
MapDialogFragment frag = new MapDialogFragment();
Bundle args = new Bundle();
args.putString("title", title);
frag.setArguments(args);
return frag;
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_dialog_map, container);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mapView = view.findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(mapboxMap -> mapboxMap.setStyle(Style.OUTDOORS));
}
@Override
public void onStart() {
super.onStart();
mapView.onStart();
}
@Override
public void onResume() {
super.onResume();
mapView.onResume();
}
@Override
public void onPause() {
super.onPause();
mapView.onPause();
}
@Override
public void onStop() {
super.onStop();
mapView.onStop();
}
@Override
public void onDestroyView() {
super.onDestroyView();
mapView.onDestroy();
mapView = null;
}
@Override
public void onLowMemory() {
super.onLowMemory();
if (mapView != null) {
mapView.onLowMemory();
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
if (mapView != null) {
mapView.onSaveInstanceState(outState);
}
}
}
}

View File

@@ -0,0 +1,131 @@
package com.mapbox.mapboxsdk.testapp.activity.maplayout;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import com.mapbox.mapboxsdk.annotations.MarkerOptions;
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.Style;
import com.mapbox.mapboxsdk.maps.UiSettings;
import com.mapbox.mapboxsdk.testapp.R;
/**
* Test activity showcasing using the map padding API.
*/
public class MapPaddingActivity extends AppCompatActivity {
private MapView mapView;
private MapboxMap mapboxMap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_padding);
mapView = findViewById(R.id.mapView);
mapView.setTag(true);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(mapboxMap -> {
MapPaddingActivity.this.mapboxMap = mapboxMap;
mapboxMap.setStyle(Style.MAPBOX_STREETS);
int paddingLeft = (int) getResources().getDimension(R.dimen.map_padding_left);
int paddingBottom = (int) getResources().getDimension(R.dimen.map_padding_bottom);
int paddingRight = (int) getResources().getDimension(R.dimen.map_padding_right);
int paddingTop = (int) getResources().getDimension(R.dimen.map_padding_top);
mapboxMap.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
UiSettings settings = mapboxMap.getUiSettings();
settings.setLogoMargins(paddingLeft, 0, 0, paddingBottom);
settings.setCompassMargins(0, paddingTop, paddingRight, 0);
settings.setAttributionEnabled(false);
moveToBangalore();
});
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_padding, menu);
return true;
}
private void moveToBangalore() {
LatLng bangalore = new LatLng(12.9810816, 77.6368034);
CameraPosition cameraPosition = new CameraPosition.Builder()
.zoom(16)
.target(bangalore)
.bearing(40)
.tilt(45)
.build();
mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
mapboxMap.addMarker(new MarkerOptions().title("Center map").position(bangalore));
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_bangalore:
if (mapboxMap != null) {
moveToBangalore();
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}

View File

@@ -0,0 +1,86 @@
package com.mapbox.mapboxsdk.testapp.activity.maplayout
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.*
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.View
import com.mapbox.mapboxsdk.maps.Style
import com.mapbox.mapboxsdk.testapp.R
import kotlinx.android.synthetic.main.activity_overlay.*
/**
* Test overlaying a Map with a View that uses a radial gradient shader.
*/
class OverlayMapActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_overlay)
mapView.onCreate(savedInstanceState)
parentView.addView(OverlayView(this))
mapView.getMapAsync {
it.setStyle(Style.MAPBOX_STREETS)
}
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
override fun onDestroy() {
super.onDestroy()
mapView.onDestroy()
}
override fun onSaveInstanceState(outState: Bundle?) {
super.onSaveInstanceState(outState)
outState?.let {
mapView.onSaveInstanceState(it)
}
}
class OverlayView(context: Context) : View(context) {
private lateinit var paint: Paint
@SuppressLint("DrawAllocation") // only happens once
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
canvas?.let {
if (!::paint.isInitialized) {
paint = Paint()
paint.color = Color.BLACK
paint.strokeWidth = 1.0f
paint.style = Paint.Style.FILL_AND_STROKE
paint.shader = RadialGradient(width / 2.0f, height / 2.0f,
height / 3.0f, Color.TRANSPARENT, Color.BLACK, Shader.TileMode.CLAMP)
}
it.drawRect(0.0f, 0.0f, width.toFloat(), height.toFloat(), paint)
}
}
}
}

View File

@@ -0,0 +1,89 @@
package com.mapbox.mapboxsdk.testapp.activity.maplayout;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.MenuItem;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.utils.NavUtils;
/**
* Test activity showcasing a simple MapView without any MapboxMap interaction.
*/
public class SimpleMapActivity extends AppCompatActivity {
private MapView mapView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_simple);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(mapboxMap -> mapboxMap.setStyle(
new Style.Builder().fromUri(Style.MAPBOX_STREETS)
));
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
// activity uses singleInstance for testing purposes
// code below provides a default navigation when using the app
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onBackPressed() {
// activity uses singleInstance for testing purposes
// code below provides a default navigation when using the app
NavUtils.navigateHome(this);
}
}

View File

@@ -0,0 +1,15 @@
package com.mapbox.mapboxsdk.testapp.activity.maplayout
import android.annotation.SuppressLint
import com.mapbox.mapboxsdk.testapp.R
/**
* TestActivity showcasing how to integrate multiple TexureView MapViews in a RecyclerView.
*/
@SuppressLint("ClickableViewAccessibility")
class TextureRecyclerViewActivity : GLSurfaceRecyclerViewActivity() {
override fun getMapItemLayoutId(): Int {
return R.layout.item_map_texture
}
}

View File

@@ -0,0 +1,144 @@
package com.mapbox.mapboxsdk.testapp.activity.maplayout;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
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.Style;
import com.mapbox.mapboxsdk.testapp.R;
/**
* Test activity showcasing visibility changes to the mapview.
*/
public class VisibilityChangeActivity extends AppCompatActivity {
private MapView mapView;
private MapboxMap mapboxMap;
private Handler handler = new Handler();
private Runnable runnable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_visibility);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(map -> {
mapboxMap = map;
mapboxMap.setStyle(Style.MAPBOX_STREETS);
mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(
new LatLng(55.754020, 37.620948), 12), 9000);
});
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
handler.post(runnable = new VisibilityRunner(mapView, findViewById(R.id.viewParent), handler));
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
private static class VisibilityRunner implements Runnable {
private MapView mapView;
private View viewParent;
private Handler handler;
private int currentStep;
VisibilityRunner(MapView mapView, View viewParent, Handler handler) {
this.mapView = mapView;
this.viewParent = viewParent;
this.handler = handler;
}
@Override
public void run() {
if (isViewHiearchyReady()) {
if (isEvenStep()) {
viewParent.setVisibility(View.VISIBLE);
mapView.setVisibility(View.VISIBLE);
} else if (isFirstOrThirdStep()) {
mapView.setVisibility(getVisibilityForStep());
} else if (isFifthOrSeventhStep()) {
viewParent.setVisibility(getVisibilityForStep());
}
updateStep();
}
handler.postDelayed(this, 1500);
}
private void updateStep() {
if (currentStep == 7) {
currentStep = 0;
} else {
currentStep++;
}
}
private int getVisibilityForStep() {
return (currentStep == 1 || currentStep == 5) ? View.GONE : View.INVISIBLE;
}
private boolean isFifthOrSeventhStep() {
return currentStep == 5 || currentStep == 7;
}
private boolean isFirstOrThirdStep() {
return currentStep == 1 || currentStep == 3;
}
private boolean isEvenStep() {
return currentStep == 0 || currentStep % 2 == 0;
}
private boolean isViewHiearchyReady() {
return mapView != null && viewParent != null;
}
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
if (runnable != null) {
handler.removeCallbacks(runnable);
runnable = null;
}
mapView.onStop();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
}

View File

@@ -0,0 +1,180 @@
package com.mapbox.mapboxsdk.testapp.activity.offline
import android.annotation.TargetApi
import android.content.Context
import android.os.Build
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.BaseAdapter
import android.widget.TextView
import android.widget.Toast
import com.mapbox.mapboxsdk.log.Logger
import com.mapbox.mapboxsdk.offline.OfflineManager
import com.mapbox.mapboxsdk.offline.OfflineRegion
import com.mapbox.mapboxsdk.storage.FileSource
import com.mapbox.mapboxsdk.testapp.R
import java.io.File
import kotlinx.android.synthetic.main.activity_change_resources_cache_path.*
class ChangeResourcesCachePathActivity : AppCompatActivity(),
AdapterView.OnItemClickListener,
FileSource.ResourcesCachePathChangeCallback {
companion object {
private const val TAG = "Mbgl-ChangeResourcesCachePathActivity"
}
private lateinit var adapter: PathAdapter
private lateinit var offlineManager: OfflineManager
private val callback = PathChangeCallback(this)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_change_resources_cache_path)
adapter = PathAdapter(this, obtainExternalFilesPaths())
listView.adapter = adapter
listView.emptyView = empty
listView.onItemClickListener = this
offlineManager = OfflineManager.getInstance(this)
}
override fun onStart() {
super.onStart()
val path: String? = FileSource.getResourcesCachePath(this)
Toast.makeText(this, "Current path: $path", Toast.LENGTH_LONG).show()
}
override fun onDestroy() {
super.onDestroy()
callback.onActivityDestroy()
}
override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
listView.onItemClickListener = null
val path: String = adapter.getItem(position) as String
FileSource.setResourcesCachePath(path, callback)
}
override fun onError(message: String) {
listView.onItemClickListener = this
Toast.makeText(this, "Error: $message", Toast.LENGTH_LONG).show()
}
override fun onSuccess(path: String) {
listView.onItemClickListener = this
Toast.makeText(this, "New path: $path", Toast.LENGTH_LONG).show()
offlineManager.listOfflineRegions(object : OfflineManager.ListOfflineRegionsCallback {
override fun onList(offlineRegions: Array<out OfflineRegion>?) {
Logger.i(TAG, "Number of saved offline regions in the new path: ${offlineRegions?.size}")
}
override fun onError(error: String?) {
Logger.e(TAG, error)
}
})
}
private fun Context.obtainExternalFilesPaths(): List<String> {
val paths = ArrayList<String>()
paths.add(this.filesDir.absolutePath)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
paths.addAll(obtainExternalFilesPathsKitKat())
} else {
paths.addAll(obtainExternalFilesPathsLegacy())
}
paths.add("${File.separator}invalid${File.separator}cache${File.separator}path")
return paths
}
private fun Context.obtainExternalFilesPathsLegacy(): List<String> {
val postFix =
"${File.separator}Android${File.separator}data${File.separator}${this.packageName}${File.separator}files"
val paths = ArrayList<String>()
val externalStorage = System.getenv("EXTERNAL_STORAGE")
val secondaryStorage = System.getenv("SECONDARY_STORAGE")
if (externalStorage != null) {
paths.add(externalStorage + postFix)
}
if (secondaryStorage != null) {
val secPaths = secondaryStorage.split(":".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
for (path in secPaths) {
paths.add(path + postFix)
}
}
return paths
}
@TargetApi(Build.VERSION_CODES.KITKAT)
private fun Context.obtainExternalFilesPathsKitKat(): List<String> {
val paths = ArrayList<String>()
val extDirs = this.getExternalFilesDirs(null)
for (dir in extDirs) {
if (dir != null) {
paths.add(dir.absolutePath)
}
}
return paths
}
private class PathChangeCallback(private var activity: ChangeResourcesCachePathActivity?) : FileSource.ResourcesCachePathChangeCallback {
override fun onSuccess(path: String) {
activity?.onSuccess(path)
}
override fun onError(message: String) {
activity?.onError(message)
}
fun onActivityDestroy() {
activity = null
}
}
class PathAdapter(private val context: Context, private val paths: List<String>) : BaseAdapter() {
override fun getItem(position: Int): Any {
return paths[position]
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getCount(): Int {
return paths.size
}
override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
val viewHolder: ViewHolder
val view: View
if (convertView == null) {
viewHolder = ViewHolder()
view = LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_1, parent, false)
viewHolder.textView = view.findViewById(android.R.id.text1)
view?.tag = viewHolder
} else {
view = convertView
viewHolder = view.tag as ViewHolder
}
viewHolder.textView?.text = paths[position]
return view
}
class ViewHolder {
var textView: TextView? = null
}
}
}

View File

@@ -0,0 +1,175 @@
package com.mapbox.mapboxsdk.testapp.activity.offline;
import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.mapbox.mapboxsdk.offline.OfflineManager;
import com.mapbox.mapboxsdk.offline.OfflineRegion;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.utils.OfflineUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Test activity showing integration of deleting an OfflineRegion.
*/
public class DeleteRegionActivity extends AppCompatActivity implements AdapterView.OnItemClickListener,
AdapterView.OnItemLongClickListener {
private OfflineRegionAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_offline_region_delete);
ListView listView = findViewById(R.id.listView);
listView.setAdapter(adapter = new OfflineRegionAdapter(this));
listView.setEmptyView(findViewById(android.R.id.empty));
listView.setOnItemClickListener(this);
listView.setOnItemLongClickListener(this);
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final OfflineRegion region = adapter.getItem(position);
String metadata = OfflineUtils.convertRegionName(region.getMetadata());
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Delete region");
final TextView input = new TextView(this);
input.setText(metadata);
builder.setView(input);
builder.setPositiveButton("OK", (dialog, which) -> delete(region));
builder.setNegativeButton("Cancel", (dialog, which) -> dialog.cancel());
builder.show();
}
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
final OfflineRegion region = adapter.getItem(position);
region.invalidate(new OfflineRegion.OfflineRegionInvalidateCallback() {
@Override
public void onInvalidate() {
Toast.makeText(DeleteRegionActivity.this, "Invalidate region success", Toast.LENGTH_SHORT).show();
}
@Override
public void onError(String error) {
Toast.makeText(DeleteRegionActivity.this, "Error:" + error, Toast.LENGTH_LONG).show();
}
});
return true;
}
private void delete(OfflineRegion region) {
region.delete(new OfflineRegion.OfflineRegionDeleteCallback() {
@Override
public void onDelete() {
Toast.makeText(
DeleteRegionActivity.this,
"Region deleted",
Toast.LENGTH_SHORT
).show();
loadOfflineRegions();
}
@Override
public void onError(String error) {
Toast.makeText(
DeleteRegionActivity.this,
"Region deletion failed with " + error,
Toast.LENGTH_LONG
).show();
}
});
}
@Override
protected void onStart() {
super.onStart();
loadOfflineRegions();
}
private void loadOfflineRegions() {
OfflineManager.getInstance(this).listOfflineRegions(new OfflineManager.ListOfflineRegionsCallback() {
@Override
public void onList(OfflineRegion[] offlineRegions) {
if (offlineRegions != null && offlineRegions.length > 0) {
adapter.setOfflineRegions(Arrays.asList(offlineRegions));
}
}
@Override
public void onError(String error) {
Toast.makeText(DeleteRegionActivity.this, "Error loading regions " + error, Toast.LENGTH_LONG).show();
}
});
}
private static class OfflineRegionAdapter extends BaseAdapter {
private Context context;
private List<OfflineRegion> offlineRegions;
OfflineRegionAdapter(Context ctx) {
context = ctx;
offlineRegions = new ArrayList<>();
}
void setOfflineRegions(List<OfflineRegion> offlineRegions) {
this.offlineRegions = offlineRegions;
notifyDataSetChanged();
}
@Override
public int getCount() {
return offlineRegions.size();
}
@Override
public OfflineRegion getItem(int position) {
return offlineRegions.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_1, parent, false);
holder.text = (TextView) convertView.findViewById(android.R.id.text1);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.text.setText(OfflineUtils.convertRegionName(getItem(position).getMetadata()));
return convertView;
}
static class ViewHolder {
TextView text;
}
}
}

View File

@@ -0,0 +1,319 @@
package com.mapbox.mapboxsdk.testapp.activity.offline
import android.os.Bundle
import android.os.Handler
import android.support.v7.app.AppCompatActivity
import android.view.View
import android.widget.ArrayAdapter
import android.widget.SeekBar
import android.widget.TextView
import android.widget.Toast
import com.mapbox.mapboxsdk.constants.MapboxConstants
import com.mapbox.mapboxsdk.geometry.LatLng
import com.mapbox.mapboxsdk.geometry.LatLngBounds
import com.mapbox.mapboxsdk.maps.Style
import com.mapbox.mapboxsdk.offline.*
import com.mapbox.mapboxsdk.testapp.R
import java.util.*
import java.util.concurrent.TimeUnit
import kotlinx.android.synthetic.main.activity_region_download.*
import timber.log.Timber
/**
* Example showcasing how to download an offline region headless, allows to test pausing and resuming the download.
*/
class DownloadRegionActivity : AppCompatActivity(), OfflineRegion.OfflineRegionObserver {
companion object {
const val STATUS_UPDATE_TIMEOUT_MS = 10_000L
}
private val handler: Handler = Handler()
private lateinit var offlineManager: OfflineManager
private var offlineRegion: OfflineRegion? = null
private var downloading = false
private var previousCompletedResourceCount: Long = 0
private var previousUpdateTimestamp: Long = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_region_download)
offlineManager = OfflineManager.getInstance(this)
offlineManager.setOfflineMapboxTileCountLimit(Long.MAX_VALUE)
initUi()
deleteOldOfflineRegions {
container.visibility = View.VISIBLE
fab.visibility = View.VISIBLE
}
}
override fun onDestroy() {
handler.removeCallbacksAndMessages(null)
offlineRegion?.setObserver(null)
super.onDestroy()
}
private fun createOfflineRegion() {
val latitudeNorth = editTextLatNorth.text.toString().toDouble()
val longitudeEast = editTextLonEast.text.toString().toDouble()
val latitudeSouth = editTextLatSouth.text.toString().toDouble()
val longitudeWest = editTextLonWest.text.toString().toDouble()
val styleUrl = spinnerStyleUrl.selectedItem as String
val maxZoom = seekbarMaxZoom.progress.toFloat()
val minZoom = seekbarMinZoom.progress.toFloat()
if (!validCoordinates(latitudeNorth, longitudeEast, latitudeSouth, longitudeWest)) {
Toast.makeText(this, "coordinates need to be in valid range", Toast.LENGTH_LONG).show()
return
}
// create offline definition from data
val definition = OfflineTilePyramidRegionDefinition(
styleUrl,
LatLngBounds.Builder()
.include(LatLng(latitudeNorth, longitudeEast))
.include(LatLng(latitudeSouth, longitudeWest))
.build(),
minZoom.toDouble(),
maxZoom.toDouble(),
resources.displayMetrics.density
)
logMessage("Creating offline region")
offlineManager.createOfflineRegion(definition, byteArrayOf(), object : OfflineManager.CreateOfflineRegionCallback {
override fun onCreate(region: OfflineRegion) {
logMessage("Region with id ${region.id} created")
offlineRegion = region
startDownload(region)
fab.visibility = View.VISIBLE
}
override fun onError(error: String) {
logMessage("Failed to create offline region: $error")
}
})
}
private fun startDownload(region: OfflineRegion) {
downloading = true
fab.setImageResource(R.drawable.ic_pause_black_24dp)
logMessage("Downloading...")
region.setObserver(this)
region.setDownloadState(OfflineRegion.STATE_ACTIVE)
previousUpdateTimestamp = System.currentTimeMillis()
handler.postDelayed(object : Runnable {
override fun run() {
if (System.currentTimeMillis() > previousUpdateTimestamp + STATUS_UPDATE_TIMEOUT_MS) {
logMessage("FAILURE! No progress in ${TimeUnit.MILLISECONDS.toSeconds(STATUS_UPDATE_TIMEOUT_MS)} seconds")
} else {
handler.postDelayed(this, 1000)
}
}
}, 1000)
}
private fun pauseDownload(region: OfflineRegion) {
downloading = false
fab.setImageResource(R.drawable.ic_play_arrow_black_24dp)
handler.removeCallbacksAndMessages(null)
region.setDownloadState(OfflineRegion.STATE_INACTIVE)
"Paused".let {
logMessage(it)
download_status.text = it
}
}
override fun onStatusChanged(status: OfflineRegionStatus) {
if (status.isComplete) {
"Completed".let {
logMessage("SUCCESS! $it")
download_status.text = it
}
fab.setImageResource(R.drawable.ic_play_arrow_black_24dp)
handler.removeCallbacksAndMessages(null)
offlineRegion?.setObserver(null)
offlineRegion?.setDownloadState(OfflineRegion.STATE_INACTIVE)
} else {
val statusText = "Downloaded ${status.completedResourceCount}/${status.requiredResourceCount}"
statusText.let {
logMessage(it)
download_status.text = it
}
if (status.completedResourceCount > status.requiredResourceCount &&
previousCompletedResourceCount <= status.requiredResourceCount
) {
logMessage("FAILURE! Completed > required")
}
}
previousCompletedResourceCount = status.completedResourceCount
previousUpdateTimestamp = System.currentTimeMillis()
}
override fun onError(error: OfflineRegionError) {
logMessage("Error: $error")
}
override fun mapboxTileCountLimitExceeded(limit: Long) {
logMessage("Error: tile count limit exceeded")
}
protected fun logMessage(message: String) {
Timber.d(message)
logView.append(message)
logView.append("\n")
}
fun deleteOldOfflineRegions(onCompleted: () -> Unit) {
offlineManager.listOfflineRegions(object : OfflineManager.ListOfflineRegionsCallback {
override fun onList(offlineRegions: Array<out OfflineRegion>) {
val count = offlineRegions.size
var remainingCount = count
if (count > 0) {
logMessage("Deleting $count old region...")
offlineRegions.forEach {
it.delete(object : OfflineRegion.OfflineRegionDeleteCallback {
override fun onDelete() {
Timber.d("Deleted region with id ${it.id}")
onProcessed()
}
override fun onError(error: String) {
Timber.e("Failed to delete region: $error")
onProcessed()
}
private fun onProcessed() {
remainingCount--
if (remainingCount == 0) {
logMessage("Done deleting")
onCompleted()
}
}
})
}
} else {
onCompleted()
}
}
override fun onError(error: String) {
logMessage("Failed to list offline regions: $error")
onCompleted()
}
})
}
// ui
private val logView: TextView by lazy {
findViewById<TextView>(R.id.log_text)
}
private fun initUi() {
initEditTexts()
initSeekbars()
initSpinner()
initZoomLevelTextviews()
initSeekbarListeners()
initFab()
}
private fun initEditTexts() {
editTextLatNorth.setText("62.0")
editTextLonEast.setText("24.0")
editTextLatSouth.setText("60.0")
editTextLonWest.setText("22.5")
}
private fun initSeekbars() {
val maxZoom = MapboxConstants.MAXIMUM_ZOOM.toInt()
seekbarMinZoom.max = maxZoom
seekbarMinZoom.progress = 1
seekbarMaxZoom.max = maxZoom
seekbarMaxZoom.progress = 15
}
private fun initSpinner() {
val styles = ArrayList<String>()
styles.add(Style.MAPBOX_STREETS)
styles.add(Style.DARK)
styles.add(Style.LIGHT)
styles.add(Style.OUTDOORS)
val spinnerArrayAdapter = ArrayAdapter(this, android.R.layout.simple_spinner_item, styles)
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
spinnerStyleUrl.adapter = spinnerArrayAdapter
}
private fun initZoomLevelTextviews() {
textViewMaxText.text = String.format("Max zoom: %s", seekbarMaxZoom.progress)
textViewMinText.text = String.format("Min zoom: %s", seekbarMinZoom.progress)
}
private fun initFab() {
fab.setOnClickListener {
container.visibility = View.GONE
if (offlineRegion == null) {
fab.visibility = View.GONE
createOfflineRegion()
} else {
offlineRegion?.let {
if (downloading) {
pauseDownload(it)
} else {
startDownload(it)
}
}
}
}
}
private fun initSeekbarListeners() {
seekbarMaxZoom.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
textViewMaxText.text = String.format("Max zoom: %s", progress)
}
override fun onStartTrackingTouch(seekBar: SeekBar) {
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
}
})
seekbarMinZoom.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
textViewMinText.text = String.format("Min zoom: %s", progress)
}
override fun onStartTrackingTouch(seekBar: SeekBar) {
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
}
})
}
private fun validCoordinates(
latitudeNorth: Double,
longitudeEast: Double,
latitudeSouth: Double,
longitudeWest: Double
): Boolean {
if (latitudeNorth < -90 || latitudeNorth > 90) {
return false
} else if (longitudeEast < -180 || longitudeEast > 180) {
return false
} else if (latitudeSouth < -90 || latitudeSouth > 90) {
return false
} else if (longitudeWest < -180 || longitudeWest > 180) {
return false
}
return true
}
}

View File

@@ -0,0 +1,147 @@
package com.mapbox.mapboxsdk.testapp.activity.offline
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.widget.Toast
import com.mapbox.mapboxsdk.Mapbox
import com.mapbox.mapboxsdk.log.Logger
import com.mapbox.mapboxsdk.maps.Style
import com.mapbox.mapboxsdk.offline.OfflineManager
import com.mapbox.mapboxsdk.offline.OfflineRegion
import com.mapbox.mapboxsdk.storage.FileSource
import com.mapbox.mapboxsdk.testapp.R
import com.mapbox.mapboxsdk.testapp.utils.FileUtils
import kotlinx.android.synthetic.main.activity_merge_offline_regions.*
class MergeOfflineRegionsActivity : AppCompatActivity() {
companion object {
private const val LOG_TAG = "Mbgl-MergeOfflineRegionsActivity"
private const val TEST_DB_FILE_NAME = "offline_test.db"
private const val TEST_STYLE = Style.SATELLITE
}
private val onFileCopiedListener = object : FileUtils.OnFileCopiedFromAssetsListener {
override fun onFileCopiedFromAssets() {
Toast.makeText(
this@MergeOfflineRegionsActivity,
String.format("OnFileCopied."),
Toast.LENGTH_LONG).show()
mergeDb()
}
override fun onError() {
Toast.makeText(
this@MergeOfflineRegionsActivity,
String.format("Error copying DB file."),
Toast.LENGTH_LONG).show()
}
}
private val onRegionMergedListener = object : OfflineManager.MergeOfflineRegionsCallback {
override fun onMerge(offlineRegions: Array<OfflineRegion>) {
mapView.getMapAsync {
it.setStyle(Style.Builder().fromUri(TEST_STYLE))
}
Toast.makeText(
this@MergeOfflineRegionsActivity,
String.format("Merged %d regions.", offlineRegions.size),
Toast.LENGTH_LONG).show()
}
override fun onError(error: String) {
Toast.makeText(
this@MergeOfflineRegionsActivity,
String.format("Offline DB merge error."),
Toast.LENGTH_LONG).show()
Logger.e(LOG_TAG, error)
}
}
/**
* Since we expect from the results of the offline merge callback to interact with the hosting activity,
* we need to ensure that we are not interacting with a destroyed activity.
*/
private class MergeCallback(private var activityCallback: OfflineManager.MergeOfflineRegionsCallback?) : OfflineManager.MergeOfflineRegionsCallback {
override fun onMerge(offlineRegions: Array<out OfflineRegion>?) {
activityCallback?.onMerge(offlineRegions)
}
override fun onError(error: String?) {
activityCallback?.onError(error)
}
fun onActivityDestroy() {
activityCallback = null
}
}
private val mergeCallback = MergeCallback(onRegionMergedListener)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_merge_offline_regions)
// forcing offline state
Mapbox.setConnected(false)
mapView.onCreate(savedInstanceState)
load_region_btn.setOnClickListener {
copyAsset()
}
mapView.getMapAsync {
it.isDebugActive = true
it.setStyle(Style.Builder().fromUri(TEST_STYLE))
}
}
private fun copyAsset() {
// copy db asset to internal memory
FileUtils.CopyFileFromAssetsTask(this, onFileCopiedListener).execute(TEST_DB_FILE_NAME, FileSource.getResourcesCachePath(this))
}
private fun mergeDb() {
OfflineManager.getInstance(this).mergeOfflineRegions(
FileSource.getResourcesCachePath(this) + "/" + TEST_DB_FILE_NAME, mergeCallback
)
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
override fun onDestroy() {
super.onDestroy()
mergeCallback.onActivityDestroy()
mapView.onDestroy()
// restoring connectivity state
Mapbox.setConnected(null)
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
mapView.onSaveInstanceState(outState)
}
}

View File

@@ -0,0 +1,320 @@
package com.mapbox.mapboxsdk.testapp.activity.offline;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Toast;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.offline.OfflineManager;
import com.mapbox.mapboxsdk.offline.OfflineRegion;
import com.mapbox.mapboxsdk.offline.OfflineRegionError;
import com.mapbox.mapboxsdk.offline.OfflineRegionStatus;
import com.mapbox.mapboxsdk.offline.OfflineTilePyramidRegionDefinition;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.model.other.OfflineDownloadRegionDialog;
import com.mapbox.mapboxsdk.testapp.model.other.OfflineListRegionsDialog;
import com.mapbox.mapboxsdk.testapp.utils.OfflineUtils;
import java.util.ArrayList;
import timber.log.Timber;
/**
* Test activity showcasing the Offline API.
* <p>
* Shows a map of Manhattan and allows the user to download and name a region.
* </p>
*/
public class OfflineActivity extends AppCompatActivity
implements OfflineDownloadRegionDialog.DownloadRegionDialogListener {
// JSON encoding/decoding
public static final String JSON_CHARSET = "UTF-8";
public static final String JSON_FIELD_REGION_NAME = "FIELD_REGION_NAME";
// Style URL
public static final String STYLE_URL = Style.MAPBOX_STREETS;
/*
* UI elements
*/
private MapView mapView;
private MapboxMap mapboxMap;
private ProgressBar progressBar;
private Button downloadRegion;
private Button listRegions;
private boolean isEndNotified;
/*
* Offline objects
*/
private OfflineManager offlineManager;
private OfflineRegion offlineRegion;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_offline);
// You can use Mapbox.setConnected(Boolean) to manually set the connectivity
// state of your app. This will override any checks performed via the ConnectivityManager.
// Mapbox.getInstance().setConnected(false);
Boolean connected = Mapbox.isConnected();
Timber.d("Mapbox is connected: %s", connected);
// Set up map
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(mapboxMap -> {
Timber.d("Map is ready");
OfflineActivity.this.mapboxMap = mapboxMap;
mapboxMap.setStyle(new Style.Builder().fromUri(STYLE_URL));
// Set initial position to UNHQ in NYC
mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(
new CameraPosition.Builder()
.target(new LatLng(40.749851, -73.967966))
.zoom(14)
.bearing(0)
.tilt(0)
.build()));
});
// The progress bar
progressBar = (ProgressBar) findViewById(R.id.progress_bar);
// Set up button listeners
downloadRegion = (Button) findViewById(R.id.button_download_region);
downloadRegion.setOnClickListener(view -> handleDownloadRegion());
listRegions = (Button) findViewById(R.id.button_list_regions);
listRegions.setOnClickListener(view -> handleListRegions());
// Set up the OfflineManager
offlineManager = OfflineManager.getInstance(this);
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
/*
* Buttons logic
*/
private void handleDownloadRegion() {
Timber.d("handleDownloadRegion");
// Show dialog
OfflineDownloadRegionDialog offlineDownloadRegionDialog = new OfflineDownloadRegionDialog();
offlineDownloadRegionDialog.show(getSupportFragmentManager(), "download");
}
private void handleListRegions() {
Timber.d("handleListRegions");
// Query the DB asynchronously
offlineManager.listOfflineRegions(new OfflineManager.ListOfflineRegionsCallback() {
@Override
public void onList(OfflineRegion[] offlineRegions) {
// Check result
if (offlineRegions == null || offlineRegions.length == 0) {
Toast.makeText(OfflineActivity.this, "You have no regions yet.", Toast.LENGTH_SHORT).show();
return;
}
// Get regions info
ArrayList<String> offlineRegionsNames = new ArrayList<>();
for (OfflineRegion offlineRegion : offlineRegions) {
offlineRegionsNames.add(OfflineUtils.convertRegionName(offlineRegion.getMetadata()));
}
// Create args
Bundle args = new Bundle();
args.putStringArrayList(OfflineListRegionsDialog.ITEMS, offlineRegionsNames);
// Show dialog
OfflineListRegionsDialog offlineListRegionsDialog = new OfflineListRegionsDialog();
offlineListRegionsDialog.setArguments(args);
offlineListRegionsDialog.show(getSupportFragmentManager(), "list");
}
@Override
public void onError(String error) {
Timber.e("Error: %s" , error);
}
});
}
/*
* Dialogs
*/
@Override
public void onDownloadRegionDialogPositiveClick(final String regionName) {
if (TextUtils.isEmpty(regionName)) {
Toast.makeText(OfflineActivity.this, "Region name cannot be empty.", Toast.LENGTH_SHORT).show();
return;
}
// Start progress bar
Timber.d("Download started: %s", regionName);
startProgress();
// Definition
LatLngBounds bounds = mapboxMap.getProjection().getVisibleRegion().latLngBounds;
double minZoom = mapboxMap.getCameraPosition().zoom;
double maxZoom = mapboxMap.getMaxZoomLevel();
float pixelRatio = this.getResources().getDisplayMetrics().density;
OfflineTilePyramidRegionDefinition definition = new OfflineTilePyramidRegionDefinition(
STYLE_URL, bounds, minZoom, maxZoom, pixelRatio);
// Sample way of encoding metadata from a JSONObject
byte[] metadata = OfflineUtils.convertRegionName(regionName);
// Create region
offlineManager.createOfflineRegion(definition, metadata, new OfflineManager.CreateOfflineRegionCallback() {
@Override
public void onCreate(OfflineRegion offlineRegion) {
Timber.d("Offline region created: %s" , regionName);
OfflineActivity.this.offlineRegion = offlineRegion;
launchDownload();
}
@Override
public void onError(String error) {
Timber.e("Error: %s", error);
}
});
}
private void launchDownload() {
// Set an observer
offlineRegion.setObserver(new OfflineRegion.OfflineRegionObserver() {
@Override
public void onStatusChanged(OfflineRegionStatus status) {
// Compute a percentage
double percentage = status.getRequiredResourceCount() >= 0
? (100.0 * status.getCompletedResourceCount() / status.getRequiredResourceCount()) :
0.0;
if (status.isComplete()) {
// Download complete
endProgress("Region downloaded successfully.");
offlineRegion.setDownloadState(OfflineRegion.STATE_INACTIVE);
offlineRegion.setObserver(null);
return;
} else if (status.isRequiredResourceCountPrecise()) {
// Switch to determinate state
setPercentage((int) Math.round(percentage));
}
// Debug
Timber.d("%s/%s resources; %s bytes downloaded.",
String.valueOf(status.getCompletedResourceCount()),
String.valueOf(status.getRequiredResourceCount()),
String.valueOf(status.getCompletedResourceSize()));
}
@Override
public void onError(OfflineRegionError error) {
Timber.e("onError: %s, %s", error.getReason(), error.getMessage());
offlineRegion.setDownloadState(OfflineRegion.STATE_INACTIVE);
}
@Override
public void mapboxTileCountLimitExceeded(long limit) {
Timber.e("Mapbox tile count limit exceeded: %s", limit);
offlineRegion.setDownloadState(OfflineRegion.STATE_INACTIVE);
}
});
// Change the region state
offlineRegion.setDownloadState(OfflineRegion.STATE_ACTIVE);
}
/*
* Progress bar
*/
private void startProgress() {
// Disable buttons
downloadRegion.setEnabled(false);
listRegions.setEnabled(false);
// Start and show the progress bar
isEndNotified = false;
progressBar.setIndeterminate(true);
progressBar.setVisibility(View.VISIBLE);
}
private void setPercentage(final int percentage) {
progressBar.setIndeterminate(false);
progressBar.setProgress(percentage);
}
private void endProgress(final String message) {
// Don't notify more than once
if (isEndNotified) {
return;
}
// Enable buttons
downloadRegion.setEnabled(true);
listRegions.setEnabled(true);
// Stop and hide the progress bar
isEndNotified = true;
progressBar.setIndeterminate(false);
progressBar.setVisibility(View.GONE);
// Show a toast
Toast.makeText(OfflineActivity.this, message, Toast.LENGTH_LONG).show();
}
}

View File

@@ -0,0 +1,187 @@
package com.mapbox.mapboxsdk.testapp.activity.offline;
import android.content.Context;
import android.os.Bundle;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.text.InputType;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.offline.OfflineManager;
import com.mapbox.mapboxsdk.offline.OfflineRegion;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.utils.OfflineUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* Test activity showing integration of updating metadata of an OfflineRegion.
*/
public class UpdateMetadataActivity extends AppCompatActivity implements AdapterView.OnItemClickListener,
AdapterView.OnItemLongClickListener {
private OfflineRegionMetadataAdapter adapter;
private MapView mapView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_metadata_update);
ListView listView = findViewById(R.id.listView);
listView.setAdapter(adapter = new OfflineRegionMetadataAdapter(this));
listView.setEmptyView(findViewById(android.R.id.empty));
listView.setOnItemClickListener(this);
listView.setOnItemLongClickListener(this);
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final OfflineRegion region = adapter.getItem(position);
String metadata = OfflineUtils.convertRegionName(region.getMetadata());
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Rename metadata");
final EditText input = new EditText(this);
input.setText(metadata);
input.setInputType(InputType.TYPE_CLASS_TEXT);
if (metadata != null) {
input.setSelection(metadata.length());
}
builder.setView(input);
builder.setPositiveButton("OK", (dialog, which) ->
updateMetadata(region, OfflineUtils.convertRegionName(input.getText().toString()))
);
builder.setNegativeButton("Cancel", (dialog, which) -> dialog.cancel());
builder.show();
}
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
ViewGroup container = findViewById(R.id.container);
container.removeAllViews();
container.addView(mapView = new MapView(view.getContext()));
mapView.onCreate(null);
mapView.getMapAsync(map -> map.setOfflineRegionDefinition(adapter.getItem(position).getDefinition()));
mapView.onStart();
mapView.onResume();
return true;
}
private void updateMetadata(OfflineRegion region, byte[] metadata) {
region.updateMetadata(metadata, new OfflineRegion.OfflineRegionUpdateMetadataCallback() {
@Override
public void onUpdate(byte[] metadata) {
adapter.notifyDataSetChanged();
}
@Override
public void onError(String error) {
Toast.makeText(
UpdateMetadataActivity.this,
"Region metadata update failed with " + error,
Toast.LENGTH_LONG
).show();
}
});
}
@Override
protected void onStart() {
super.onStart();
loadOfflineRegions();
}
private void loadOfflineRegions() {
OfflineManager.getInstance(this).listOfflineRegions(new OfflineManager.ListOfflineRegionsCallback() {
@Override
public void onList(OfflineRegion[] offlineRegions) {
if (offlineRegions != null && offlineRegions.length > 0) {
adapter.setOfflineRegions(Arrays.asList(offlineRegions));
}
}
@Override
public void onError(String error) {
Toast.makeText(UpdateMetadataActivity.this, "Error loading regions " + error, Toast.LENGTH_LONG).show();
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mapView != null) {
mapView.onPause();
mapView.onStop();
mapView.onDestroy();
}
}
private static class OfflineRegionMetadataAdapter extends BaseAdapter {
private Context context;
private List<OfflineRegion> offlineRegions;
OfflineRegionMetadataAdapter(Context ctx) {
context = ctx;
offlineRegions = new ArrayList<>();
}
void setOfflineRegions(List<OfflineRegion> offlineRegions) {
this.offlineRegions = offlineRegions;
notifyDataSetChanged();
}
@Override
public int getCount() {
return offlineRegions.size();
}
@Override
public OfflineRegion getItem(int position) {
return offlineRegions.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
if (convertView == null) {
holder = new ViewHolder();
convertView = LayoutInflater.from(context).inflate(android.R.layout.simple_list_item_1, parent, false);
holder.text = (TextView) convertView.findViewById(android.R.id.text1);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
holder.text.setText(OfflineUtils.convertRegionName(getItem(position).getMetadata()));
return convertView;
}
static class ViewHolder {
TextView text;
}
}
}

View File

@@ -0,0 +1,366 @@
package com.mapbox.mapboxsdk.testapp.activity.render;
import android.content.res.AssetManager;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.Gravity;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.mapbox.mapboxsdk.snapshotter.MapSnapshotter;
import okio.BufferedSource;
import okio.Okio;
import timber.log.Timber;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Activity that generates map snapshots based on the node render test suite.
*/
public class RenderTestActivity extends AppCompatActivity {
private static final String TEST_BASE_PATH = "integration";
private static final String RENDER_TEST_BASE_PATH = TEST_BASE_PATH + "/render-tests";
// We additionally read out excluded tests from `/platform/node/test/ignore.json`
private static final List<String> EXCLUDED_TESTS = new ArrayList<String>() {
{
add("overlay,background-opacity");
add("collision-lines-pitched,debug");
add("1024-circle,extent");
add("empty,empty");
add("rotation-alignment-map,icon-pitch-scaling");
add("rotation-alignment-viewport,icon-pitch-scaling");
add("pitch15,line-pitch");
add("pitch30,line-pitch");
add("line-placement-true-pitched,text-keep-upright");
add("180,raster-rotation");
add("45,raster-rotation");
add("90,raster-rotation");
add("overlapping,raster-masking");
add("missing,raster-loading");
add("pitchAndBearing,line-pitch");
add("overdraw,sparse-tileset");
}
};
private final Map<RenderTestDefinition, Bitmap> renderResultMap = new HashMap<>();
private List<RenderTestDefinition> renderTestDefinitions;
private OnRenderTestCompletionListener onRenderTestCompletionListener;
private MapSnapshotter mapSnapshotter;
private ImageView imageView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(imageView = new ImageView(RenderTestActivity.this));
imageView.setLayoutParams(new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT, Gravity.CENTER)
);
}
@Override
protected void onStop() {
super.onStop();
if (mapSnapshotter != null) {
mapSnapshotter.cancel();
}
}
//
// Loads the ignore tests from assets folder
//
private static class LoadRenderIgnoreTask extends AsyncTask<Void, Void, List<String>> {
private WeakReference<RenderTestActivity> renderTestActivityWeakReference;
LoadRenderIgnoreTask(RenderTestActivity renderTestActivity) {
this.renderTestActivityWeakReference = new WeakReference<>(renderTestActivity);
}
@Override
protected List<String> doInBackground(Void... voids) {
return loadIgnoreList(renderTestActivityWeakReference.get().getAssets());
}
@Override
protected void onPostExecute(List<String> strings) {
super.onPostExecute(strings);
if (renderTestActivityWeakReference.get() != null) {
renderTestActivityWeakReference.get().onLoadIgnoreList(strings);
}
}
}
//
// Loads the render test definitions from assets folder
//
private static class LoadRenderDefinitionTask extends AsyncTask<Void, Void, List<RenderTestDefinition>> {
private WeakReference<RenderTestActivity> renderTestActivityWeakReference;
LoadRenderDefinitionTask(RenderTestActivity renderTestActivity) {
this.renderTestActivityWeakReference = new WeakReference<>(renderTestActivity);
}
@Override
protected List<RenderTestDefinition> doInBackground(Void... voids) {
List<RenderTestDefinition> definitions = new ArrayList<>();
AssetManager assetManager = renderTestActivityWeakReference.get().getAssets();
String[] categories = new String[0];
try {
categories = assetManager.list(RENDER_TEST_BASE_PATH);
} catch (IOException exception) {
Timber.e(exception);
}
for (int counter = categories.length - 1; counter >= 0; counter--) {
try {
String[] tests = assetManager.list(String.format("%s/%s", RENDER_TEST_BASE_PATH, categories[counter]));
for (String test : tests) {
String styleJson = loadStyleJson(assetManager, categories[counter], test);
RenderTestStyleDefinition renderTestStyleDefinition = new Gson()
.fromJson(styleJson, RenderTestStyleDefinition.class);
RenderTestDefinition definition = new RenderTestDefinition(
categories[counter], test, styleJson, renderTestStyleDefinition);
if (!definition.hasOperations()) {
if (!EXCLUDED_TESTS.contains(definition.getName() + "," + definition.getCategory())) {
definitions.add(definition);
}
} else {
Timber.e("could not add test, test requires operations: %s from %s", test, categories[counter]);
}
}
} catch (Exception exception) {
Timber.e(exception);
}
}
return definitions;
}
@Override
protected void onPostExecute(List<RenderTestDefinition> renderTestDefinitions) {
super.onPostExecute(renderTestDefinitions);
RenderTestActivity renderTestActivity = renderTestActivityWeakReference.get();
if (renderTestActivity != null) {
renderTestActivity.startRenderTests(renderTestDefinitions);
}
}
}
private static List<String> loadIgnoreList(AssetManager assets) {
List<String> ignores = new ArrayList<>();
try (InputStream input = assets.open(String.format("%s/ignores.json", TEST_BASE_PATH))) {
BufferedSource source = Okio.buffer(Okio.source(input));
String styleJson = source.readByteString().string(Charset.forName("utf-8"));
JsonObject object = new Gson().fromJson(styleJson, JsonObject.class);
for (Map.Entry<String, JsonElement> stringJsonElementEntry : object.entrySet()) {
String[] parts = stringJsonElementEntry.getKey().split("/");
ignores.add(String.format("%s,%s", parts[2], parts[1]));
}
} catch (IOException exception) {
Timber.e(exception);
}
return ignores;
}
private static String loadStyleJson(AssetManager assets, String category, String test) {
String styleJson = null;
try (InputStream input = assets.open(String.format("%s/%s/%s/style.json", RENDER_TEST_BASE_PATH, category, test))) {
BufferedSource source = Okio.buffer(Okio.source(input));
styleJson = source.readByteString().string(Charset.forName("utf-8"));
} catch (IOException exception) {
Timber.e(exception);
}
return styleJson;
}
private void startRenderTests(List<RenderTestDefinition> renderTestDefinitions) {
this.renderTestDefinitions = renderTestDefinitions;
if (!renderTestDefinitions.isEmpty()) {
render(renderTestDefinitions.get(0), renderTestDefinitions.size());
} else {
// no definitions, finish test without rendering
onRenderTestCompletionListener.onFinish();
}
}
private void render(final RenderTestDefinition renderTestDefinition, final int testSize) {
Timber.d("Render test %s,%s", renderTestDefinition.getName(), renderTestDefinition.getCategory());
mapSnapshotter = new RenderTestSnapshotter(this, renderTestDefinition.toOptions());
mapSnapshotter.start(result -> {
Bitmap snapshot = result.getBitmap();
imageView.setImageBitmap(snapshot);
renderResultMap.put(renderTestDefinition, snapshot);
if (renderResultMap.size() != testSize) {
continueTesting(renderTestDefinition);
} else {
finishTesting();
}
}, error -> Timber.e(error));
}
private void continueTesting(RenderTestDefinition renderTestDefinition) {
int next = renderTestDefinitions.indexOf(renderTestDefinition) + 1;
Timber.d("Next test: %s / %s", next, renderTestDefinitions.size());
render(renderTestDefinitions.get(next), renderTestDefinitions.size());
}
private void finishTesting() {
new SaveResultToDiskTask(onRenderTestCompletionListener, renderResultMap).execute();
}
//
// Save tests results to disk
//
private static class SaveResultToDiskTask extends AsyncTask<Void, Void, Void> {
private OnRenderTestCompletionListener onRenderTestCompletionListener;
private Map<RenderTestDefinition, Bitmap> renderResultMap;
SaveResultToDiskTask(OnRenderTestCompletionListener onRenderTestCompletionListener,
Map<RenderTestDefinition, Bitmap> renderResultMap) {
this.onRenderTestCompletionListener = onRenderTestCompletionListener;
this.renderResultMap = renderResultMap;
}
@Override
protected Void doInBackground(Void... voids) {
if (isExternalStorageWritable()) {
try {
File testResultDir = FileUtils.createTestResultRootFolder();
String basePath = testResultDir.getAbsolutePath();
for (Map.Entry<RenderTestDefinition, Bitmap> testResult : renderResultMap.entrySet()) {
writeResultToDisk(basePath, testResult);
}
} catch (final Exception exception) {
Timber.e(exception);
}
}
return null;
}
private void writeResultToDisk(String path, Map.Entry<RenderTestDefinition, Bitmap> result) {
RenderTestDefinition definition = result.getKey();
String categoryName = definition.getCategory();
String categoryPath = String.format("%s/%s", path, categoryName);
FileUtils.createCategoryDirectory(categoryPath);
String testName = result.getKey().getName();
String testDir = FileUtils.createTestDirectory(categoryPath, testName);
FileUtils.writeTestResultToDisk(testDir, result.getValue());
}
private boolean isExternalStorageWritable() {
return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
if (onRenderTestCompletionListener != null) {
onRenderTestCompletionListener.onFinish();
}
}
}
//
// Callback configuration to notify test executor of test finishing
//
public interface OnRenderTestCompletionListener {
void onFinish();
}
public void setOnRenderTestCompletionListener(OnRenderTestCompletionListener listener) {
this.onRenderTestCompletionListener = listener;
new LoadRenderIgnoreTask(this).execute();
}
public void onLoadIgnoreList(List<String> ignoreList) {
Timber.e("We loaded %s of tests to be ignored", ignoreList.size());
EXCLUDED_TESTS.addAll(ignoreList);
new LoadRenderDefinitionTask(this).execute();
}
//
// FileUtils
//
private static class FileUtils {
private static void createCategoryDirectory(String catPath) {
File testResultDir = new File(catPath);
if (testResultDir.exists()) {
return;
}
if (!testResultDir.mkdirs()) {
throw new RuntimeException("can't create root test directory");
}
}
private static File createTestResultRootFolder() {
File testResultDir = new File(Environment.getExternalStorageDirectory()
+ File.separator + "mapbox" + File.separator + "render");
if (testResultDir.exists()) {
// cleanup old files
deleteRecursive(testResultDir);
}
if (!testResultDir.mkdirs()) {
throw new RuntimeException("can't create root test directory");
}
return testResultDir;
}
private static void deleteRecursive(File fileOrDirectory) {
if (fileOrDirectory.isDirectory()) {
File[] files = fileOrDirectory.listFiles();
if (files != null) {
for (File file : files) {
deleteRecursive(file);
}
}
}
if (!fileOrDirectory.delete()) {
Timber.e("can't delete directory");
}
}
private static String createTestDirectory(String basePath, String testName) {
File testDir = new File(basePath + "/" + testName);
if (!testDir.exists()) {
if (!testDir.mkdir()) {
throw new RuntimeException("can't create sub directory for " + testName);
}
}
return testDir.getAbsolutePath();
}
private static void writeTestResultToDisk(String testPath, Bitmap testResult) {
String filePath = testPath + "/actual.png";
try (FileOutputStream out = new FileOutputStream(filePath)) {
testResult.compress(Bitmap.CompressFormat.PNG, 100, out);
} catch (IOException exception) {
Timber.e(exception);
}
}
}
}

View File

@@ -0,0 +1,91 @@
package com.mapbox.mapboxsdk.testapp.activity.render;
import com.mapbox.mapboxsdk.snapshotter.MapSnapshotter;
public class RenderTestDefinition {
private static final int DEFAULT_WIDTH = 512;
private static final int DEFAULT_HEIGHT = 512;
private String category; // eg. background-color
private String name; // eg. colorSpace-hcl
private String styleJson;
private RenderTestStyleDefinition definition;
RenderTestDefinition(String category, String name, String styleJson, RenderTestStyleDefinition definition) {
this.category = category;
this.name = name;
this.styleJson = styleJson;
this.definition = definition;
}
public String getName() {
return name;
}
public String getCategory() {
return category;
}
public int getWidth() {
RenderTestStyleDefinition.Test test = getTest();
if (test != null) {
Integer testWidth = test.getWidth();
if (testWidth != null && testWidth > 0) {
return testWidth;
}
}
return DEFAULT_WIDTH;
}
public int getHeight() {
RenderTestStyleDefinition.Test test = getTest();
if (test != null) {
Integer testHeight = test.getHeight();
if (testHeight != null && testHeight > 0) {
return testHeight;
}
}
return DEFAULT_HEIGHT;
}
public float getPixelRatio() {
RenderTestStyleDefinition.Test test = getTest();
if (test != null) {
Float pixelRatio = test.getPixelRatio();
if (pixelRatio != null && pixelRatio > 0) {
return pixelRatio;
}
}
return 1;
}
public String getStyleJson() {
return styleJson;
}
public boolean hasOperations() {
return getTest().getOperations() != null;
}
public RenderTestStyleDefinition.Test getTest() {
return definition.getMetadata().getTest();
}
public MapSnapshotter.Options toOptions() {
return new MapSnapshotter
.Options(getWidth(), getHeight())
.withStyleJson(styleJson)
.withPixelRatio(getPixelRatio())
.withLogo(false);
}
@Override
public String toString() {
return "RenderTestDefinition{"
+ "category='" + category + '\''
+ ", name='" + name + '\''
+ ", styleJson='" + styleJson + '\''
+ '}';
}
}

View File

@@ -0,0 +1,18 @@
package com.mapbox.mapboxsdk.testapp.activity.render;
import android.content.Context;
import android.support.annotation.NonNull;
import com.mapbox.mapboxsdk.snapshotter.MapSnapshot;
import com.mapbox.mapboxsdk.snapshotter.MapSnapshotter;
public class RenderTestSnapshotter extends MapSnapshotter {
RenderTestSnapshotter(@NonNull Context context, @NonNull Options options) {
super(context, options);
}
@Override
protected void addOverlay(MapSnapshot mapSnapshot) {
// don't add an overlay
}
}

View File

@@ -0,0 +1,131 @@
package com.mapbox.mapboxsdk.testapp.activity.render;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class RenderTestStyleDefinition {
private Integer version;
private Metadata metadata;
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
public Integer getVersion() {
return version;
}
public void setVersion(Integer version) {
this.version = version;
}
public Metadata getMetadata() {
return metadata;
}
public void setMetadata(Metadata metadata) {
this.metadata = metadata;
}
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
public class Metadata {
private Test test;
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
public Test getTest() {
return test;
}
public void setTest(Test test) {
this.test = test;
}
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
}
public class Test {
private Integer width;
private Integer height;
private Float pixelRatio;
private List<Integer> center = null;
private Integer zoom;
private Double diff;
private List<List<String>> operations = null;
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
public Integer getWidth() {
return width;
}
public void setWidth(Integer width) {
this.width = width;
}
public Integer getHeight() {
return height;
}
public void setHeight(Integer height) {
this.height = height;
}
public Float getPixelRatio() {
return pixelRatio;
}
public List<Integer> getCenter() {
return center;
}
public void setCenter(List<Integer> center) {
this.center = center;
}
public Integer getZoom() {
return zoom;
}
public void setZoom(Integer zoom) {
this.zoom = zoom;
}
public Double getDiff() {
return diff;
}
public void setDiff(Double diff) {
this.diff = diff;
}
public List<List<String>> getOperations() {
return operations;
}
public void setOperations(List<List<String>> operations) {
this.operations = operations;
}
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
}
}

View File

@@ -0,0 +1,127 @@
package com.mapbox.mapboxsdk.testapp.activity.snapshot;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.ViewTreeObserver;
import android.widget.GridLayout;
import android.widget.ImageView;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.snapshotter.MapSnapshotter;
import com.mapbox.mapboxsdk.testapp.R;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import timber.log.Timber;
/**
* Test activity showing how to use a the {@link com.mapbox.mapboxsdk.snapshotter.MapSnapshotter}
*/
public class MapSnapshotterActivity extends AppCompatActivity {
private GridLayout grid;
private List<MapSnapshotter> snapshotters = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_snapshotter);
// Find the grid view and start snapshotting as soon
// as the view is measured
grid = findViewById(R.id.snapshot_grid);
grid.getViewTreeObserver()
.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
//noinspection deprecation
grid.getViewTreeObserver().removeGlobalOnLayoutListener(this);
addSnapshots();
}
});
}
private void addSnapshots() {
Timber.i("Creating snapshotters");
for (int row = 0; row < grid.getRowCount(); row++) {
for (int column = 0; column < grid.getColumnCount(); column++) {
startSnapShot(row, column);
}
}
}
private void startSnapShot(final int row, final int column) {
// Define the dimensions
MapSnapshotter.Options options = new MapSnapshotter.Options(
grid.getMeasuredWidth() / grid.getColumnCount(),
grid.getMeasuredHeight() / grid.getRowCount()
)
// Optionally the pixel ratio
.withPixelRatio(1)
// Optionally the style
.withStyle((column + row) % 2 == 0 ? Style.MAPBOX_STREETS : Style.DARK)
.withLocalIdeographFontFamily(MapboxConstants.DEFAULT_FONT);
// Optionally the visible region
if (row % 2 == 0) {
options.withRegion(new LatLngBounds.Builder()
.include(new LatLng(randomInRange(-80, 80), randomInRange(-160, 160)))
.include(new LatLng(randomInRange(-80, 80), randomInRange(-160, 160)))
.build()
);
}
// Optionally the camera options
if (column % 2 == 0) {
options.withCameraPosition(new CameraPosition.Builder()
.target(options.getRegion() != null
? options.getRegion().getCenter()
: new LatLng(randomInRange(-80, 80), randomInRange(-160, 160)))
.bearing(randomInRange(0, 360))
.tilt(randomInRange(0, 60))
.zoom(randomInRange(0, 20))
.build()
);
}
MapSnapshotter snapshotter = new MapSnapshotter(MapSnapshotterActivity.this, options);
snapshotter.start(snapshot -> {
Timber.i("Got the snapshot");
ImageView imageView = new ImageView(MapSnapshotterActivity.this);
imageView.setImageBitmap(snapshot.getBitmap());
grid.addView(
imageView,
new GridLayout.LayoutParams(GridLayout.spec(row), GridLayout.spec(column))
);
});
snapshotters.add(snapshotter);
}
@Override
public void onPause() {
super.onPause();
// Make sure to stop the snapshotters on pause
for (MapSnapshotter snapshotter : snapshotters) {
snapshotter.cancel();
}
snapshotters.clear();
}
private static Random random = new Random();
public static float randomInRange(float min, float max) {
return (random.nextFloat() * (max - min)) + min;
}
}

View File

@@ -0,0 +1,71 @@
package com.mapbox.mapboxsdk.testapp.activity.snapshot;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.snapshotter.MapSnapshot;
import com.mapbox.mapboxsdk.snapshotter.MapSnapshotter;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.utils.ResourceUtils;
import timber.log.Timber;
import java.io.IOException;
/**
* Test activity showing how to use a the MapSnapshotter with a local style
*/
public class MapSnapshotterLocalStyleActivity extends AppCompatActivity
implements MapSnapshotter.SnapshotReadyCallback {
private MapSnapshotter mapSnapshotter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_snapshotter_marker);
final View container = findViewById(R.id.container);
container.getViewTreeObserver()
.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
//noinspection deprecation
container.getViewTreeObserver().removeGlobalOnLayoutListener(this);
String styleJson;
try {
styleJson = ResourceUtils.readRawResource(MapSnapshotterLocalStyleActivity.this, R.raw.sat_style);
} catch (IOException exception) {
throw new RuntimeException(exception);
}
Timber.i("Starting snapshot");
mapSnapshotter = new MapSnapshotter(
getApplicationContext(),
new MapSnapshotter
.Options(Math.min(container.getMeasuredWidth(), 1024), Math.min(container.getMeasuredHeight(), 1024))
.withStyleJson(styleJson)
.withCameraPosition(new CameraPosition.Builder().target(new LatLng(52.090737, 5.121420)).zoom(18).build())
);
mapSnapshotter.start(MapSnapshotterLocalStyleActivity.this, error -> Timber.e(error));
}
});
}
@Override
protected void onStop() {
super.onStop();
mapSnapshotter.cancel();
}
@Override
public void onSnapshotReady(MapSnapshot snapshot) {
Timber.i("Snapshot ready");
ImageView imageView = (ImageView) findViewById(R.id.snapshot_image);
imageView.setImageBitmap(snapshot.getBitmap());
}
}

View File

@@ -0,0 +1,105 @@
package com.mapbox.mapboxsdk.testapp.activity.snapshot;
import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.PointF;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.support.v7.app.AppCompatActivity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.snapshotter.MapSnapshot;
import com.mapbox.mapboxsdk.snapshotter.MapSnapshotter;
import com.mapbox.mapboxsdk.testapp.R;
import timber.log.Timber;
/**
* Test activity showing how to use a the {@link MapSnapshotter} and overlay
* {@link android.graphics.Bitmap}s on top.
*/
public class MapSnapshotterMarkerActivity extends AppCompatActivity implements MapSnapshotter.SnapshotReadyCallback {
private MapSnapshotter mapSnapshotter;
private MapSnapshot mapSnapshot;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_snapshotter_marker);
final View container = findViewById(R.id.container);
container.getViewTreeObserver()
.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
//noinspection deprecation
container.getViewTreeObserver().removeGlobalOnLayoutListener(this);
Timber.i("Starting snapshot");
mapSnapshotter = new MapSnapshotter(
getApplicationContext(),
new MapSnapshotter
.Options(Math.min(container.getMeasuredWidth(), 1024), Math.min(container.getMeasuredHeight(), 1024))
.withStyle(Style.OUTDOORS)
.withCameraPosition(new CameraPosition.Builder().target(new LatLng(52.090737, 5.121420)).zoom(15).build())
);
mapSnapshotter.start(MapSnapshotterMarkerActivity.this);
}
});
}
@Override
protected void onStop() {
super.onStop();
mapSnapshotter.cancel();
}
@SuppressLint("ClickableViewAccessibility")
@Override
public void onSnapshotReady(MapSnapshot snapshot) {
this.mapSnapshot = snapshot;
Timber.i("Snapshot ready");
ImageView imageView = (ImageView) findViewById(R.id.snapshot_image);
Bitmap image = addMarker(snapshot);
imageView.setImageBitmap(image);
imageView.setOnTouchListener((v, event) -> {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
LatLng latLng = snapshot.latLngForPixel(new PointF(event.getX(), event.getY()));
Timber.e("Clicked LatLng is %s", latLng);
return true;
}
return false;
});
}
private Bitmap addMarker(MapSnapshot snapshot) {
Canvas canvas = new Canvas(snapshot.getBitmap());
Bitmap marker = BitmapFactory.decodeResource(getResources(), R.drawable.mapbox_marker_icon_default, null);
// Dom toren
PointF markerLocation = snapshot.pixelForLatLng(new LatLng(52.090649433011315, 5.121310651302338));
canvas.drawBitmap(marker,
/* Subtract half of the width so we center the bitmap correctly */
markerLocation.x - marker.getWidth() / 2,
/* Subtract half of the height so we align the bitmap bottom correctly */
markerLocation.y - marker.getHeight() / 2,
null
);
return snapshot.getBitmap();
}
@VisibleForTesting
@Nullable
public MapSnapshot getMapSnapshot() {
return mapSnapshot;
}
}

View File

@@ -0,0 +1,103 @@
package com.mapbox.mapboxsdk.testapp.activity.snapshot;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ImageView;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.snapshotter.MapSnapshot;
import com.mapbox.mapboxsdk.snapshotter.MapSnapshotter;
import com.mapbox.mapboxsdk.testapp.R;
import java.util.Random;
/**
* Test activity showing how to use a the {@link MapSnapshotter}
*/
public class MapSnapshotterReuseActivity extends AppCompatActivity implements MapSnapshotter.SnapshotReadyCallback {
private MapSnapshotter mapSnapshotter;
private View fab;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_snapshotter_reuse);
fab = findViewById(R.id.fab);
fab.setVisibility(View.INVISIBLE);
fab.setOnClickListener(v -> {
fab.setVisibility(View.INVISIBLE);
mapSnapshotter.setStyleUrl(getRandomStyle());
if (random.nextInt(2) == 0) {
mapSnapshotter.setCameraPosition(getRandomCameraPosition());
} else {
mapSnapshotter.setRegion(getRandomBounds());
}
if (random.nextInt(2) == 0) {
mapSnapshotter.setSize(512, 512);
} else {
mapSnapshotter.setSize(256, 256);
}
mapSnapshotter.start(MapSnapshotterReuseActivity.this);
});
mapSnapshotter = new MapSnapshotter(
getApplicationContext(),
new MapSnapshotter.Options(512, 512)
);
mapSnapshotter.start(MapSnapshotterReuseActivity.this);
}
@Override
public void onSnapshotReady(MapSnapshot snapshot) {
fab.setVisibility(View.VISIBLE);
ImageView imageView = findViewById(R.id.snapshot_image);
imageView.setImageBitmap(snapshot.getBitmap());
}
private LatLngBounds getRandomBounds() {
return new LatLngBounds.Builder()
.include(new LatLng(randomInRange(5, 10), randomInRange(-5, 5)))
.include(new LatLng(randomInRange(-5, 5), randomInRange(5, 10)))
.build();
}
private CameraPosition getRandomCameraPosition() {
return new CameraPosition.Builder()
.target(new LatLng(randomInRange(-80, 80), randomInRange(-160, 160)))
.zoom(randomInRange(2, 10))
.bearing(randomInRange(0, 90))
.build();
}
public String getRandomStyle() {
switch (random.nextInt(5)) {
case 0:
return Style.DARK;
case 1:
return Style.LIGHT;
case 2:
return Style.MAPBOX_STREETS;
case 3:
return Style.OUTDOORS;
case 4:
return Style.SATELLITE_STREETS;
default:
return Style.TRAFFIC_DAY;
}
}
private static Random random = new Random();
public static float randomInRange(float min, float max) {
return (random.nextFloat() * (max - min)) + min;
}
}

View File

@@ -0,0 +1,77 @@
package com.mapbox.mapboxsdk.testapp.activity.storage
import android.os.Bundle
import android.os.Looper
import android.support.design.widget.Snackbar
import android.support.v7.app.AppCompatActivity
import com.mapbox.mapboxsdk.offline.OfflineManager
import com.mapbox.mapboxsdk.testapp.R
import kotlinx.android.synthetic.main.activity_cache_management.*
/**
* Test activity showcasing the cache management APIs
*/
class CacheManagementActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_cache_management)
val fileSource = OfflineManager.getInstance(this)
resetDatabaseButton.setOnClickListener {
fileSource.resetDatabase(object : OfflineManager.FileSourceCallback {
override fun onSuccess() {
showSnackbar("Reset database success")
}
override fun onError(message: String) {
showSnackbar("Reset database fail: $message")
}
})
}
invalidateAmbientCacheButton.setOnClickListener {
fileSource.invalidateAmbientCache(object : OfflineManager.FileSourceCallback {
override fun onSuccess() {
showSnackbar("Invalidate ambient cache success")
}
override fun onError(message: String) {
showSnackbar("Invalidate ambient cache fail: $message")
}
})
}
clearAmbientCacheButton.setOnClickListener {
fileSource.clearAmbientCache(object : OfflineManager.FileSourceCallback {
override fun onSuccess() {
showSnackbar("Clear ambient cache success")
}
override fun onError(message: String) {
showSnackbar("Clear ambient cache fail: $message")
}
})
}
setMaximumAmbientCacheSizeButton.setOnClickListener {
fileSource.setMaximumAmbientCacheSize(5000000, object : OfflineManager.FileSourceCallback {
override fun onSuccess() {
showSnackbar("Set maximum ambient cache size success")
}
override fun onError(message: String) {
showSnackbar("Set maximum ambient cache size fail: $message")
}
})
}
}
fun showSnackbar(message: String) {
// validate that all callbacks occur on main thread
assert(Looper.myLooper() == Looper.getMainLooper())
// show snackbar
Snackbar.make(container, message, Snackbar.LENGTH_SHORT).show()
}
}

View File

@@ -0,0 +1,99 @@
package com.mapbox.mapboxsdk.testapp.activity.storage;
import android.app.Activity;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.storage.FileSource;
import com.mapbox.mapboxsdk.storage.Resource;
import com.mapbox.mapboxsdk.testapp.R;
import timber.log.Timber;
/**
* Test activity showcasing the url transform
*/
public class UrlTransformActivity extends AppCompatActivity {
private MapView mapView;
/**
* Be sure to use an isolated class so the activity is not leaked when
* the activity goes out of scope (static class in this case).
* <p>
* Alternatively, unregister the callback in {@link Activity#onDestroy()}
*/
private static final class Transform implements FileSource.ResourceTransformCallback {
@Override
public String onURL(@Resource.Kind int kind, String url) {
Timber.i("[%s] Could be rewriting %s", Thread.currentThread().getName(), url);
return url;
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_data_driven_style);
// Initialize map as normal
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
// Get a handle to the file source and set the resource transform
FileSource.getInstance(UrlTransformActivity.this).setResourceTransform(new Transform());
mapView.getMapAsync(map -> {
Timber.i("Map loaded");
map.setStyle(Style.MAPBOX_STREETS);
});
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
// Example of how to reset the transform callback
FileSource.getInstance(UrlTransformActivity.this).setResourceTransform(null);
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}

View File

@@ -0,0 +1,143 @@
package com.mapbox.mapboxsdk.testapp.activity.style;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngQuad;
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.RasterLayer;
import com.mapbox.mapboxsdk.style.sources.ImageSource;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.utils.BitmapUtils;
/**
* Test activity showing how to use a series of images to create an animation
* with an ImageSource
* <p>
* GL-native equivalent of https://www.mapbox.com/mapbox-gl-js/example/animate-images/
* </p>
*/
public class AnimatedImageSourceActivity extends AppCompatActivity implements OnMapReadyCallback {
private static final String ID_IMAGE_SOURCE = "animated_image_source";
private static final String ID_IMAGE_LAYER = "animated_image_layer";
private MapView mapView;
private final Handler handler = new Handler();
private Runnable runnable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_animated_image_source);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
}
@Override
public void onMapReady(@NonNull final MapboxMap map) {
LatLngQuad quad = new LatLngQuad(
new LatLng(46.437, -80.425),
new LatLng(46.437, -71.516),
new LatLng(37.936, -71.516),
new LatLng(37.936, -80.425));
final ImageSource imageSource = new ImageSource(ID_IMAGE_SOURCE, quad, R.drawable.southeast_radar_0);
final RasterLayer layer = new RasterLayer(ID_IMAGE_LAYER, ID_IMAGE_SOURCE);
map.setStyle(new Style.Builder()
.fromUri(Style.MAPBOX_STREETS)
.withSource(imageSource)
.withLayer(layer), style -> {
runnable = new RefreshImageRunnable(imageSource, handler);
handler.postDelayed(runnable, 100);
}
);
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
public void onResume() {
super.onResume();
mapView.onResume();
}
@Override
public void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
handler.removeCallbacks(runnable);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
private static class RefreshImageRunnable implements Runnable {
private ImageSource imageSource;
private Handler handler;
private Bitmap[] drawables;
private int drawableIndex;
Bitmap getBitmap(int resourceId) {
Context context = Mapbox.getApplicationContext();
Drawable drawable = BitmapUtils.getDrawableFromRes(context, resourceId);
if (drawable instanceof BitmapDrawable) {
BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
return bitmapDrawable.getBitmap();
}
return null;
}
RefreshImageRunnable(ImageSource imageSource, Handler handler) {
this.imageSource = imageSource;
this.handler = handler;
drawables = new Bitmap[4];
drawables[0] = getBitmap(R.drawable.southeast_radar_0);
drawables[1] = getBitmap(R.drawable.southeast_radar_1);
drawables[2] = getBitmap(R.drawable.southeast_radar_2);
drawables[3] = getBitmap(R.drawable.southeast_radar_3);
drawableIndex = 1;
}
@Override
public void run() {
imageSource.setImage(drawables[drawableIndex++]);
if (drawableIndex > 3) {
drawableIndex = 0;
}
handler.postDelayed(this, 1000);
}
}
}

View File

@@ -0,0 +1,151 @@
package com.mapbox.mapboxsdk.testapp.activity.style;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.style.expressions.Expression;
import com.mapbox.mapboxsdk.style.layers.FillExtrusionLayer;
import com.mapbox.mapboxsdk.style.layers.Property;
import com.mapbox.mapboxsdk.style.light.Light;
import com.mapbox.mapboxsdk.style.light.Position;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.utils.ColorUtils;
import static com.mapbox.mapboxsdk.style.expressions.Expression.eq;
import static com.mapbox.mapboxsdk.style.expressions.Expression.get;
import static com.mapbox.mapboxsdk.style.expressions.Expression.literal;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionBase;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionHeight;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionOpacity;
/**
* Test activity showing 3D buildings with a FillExtrusion Layer
*/
public class BuildingFillExtrusionActivity extends AppCompatActivity {
private MapView mapView;
private MapboxMap mapboxMap;
private Light light;
private boolean isMapAnchorLight;
private boolean isLowIntensityLight;
private boolean isRedColor;
private boolean isInitPosition;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_building_layer);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(map -> {
mapboxMap = map;
mapboxMap.setStyle(Style.MAPBOX_STREETS, style -> {
setupBuildings(style);
setupLight();
});
});
}
private void setupBuildings(Style style) {
FillExtrusionLayer fillExtrusionLayer = new FillExtrusionLayer("3d-buildings", "composite");
fillExtrusionLayer.setSourceLayer("building");
fillExtrusionLayer.setFilter(eq(get("extrude"), literal("true")));
fillExtrusionLayer.setMinZoom(15);
fillExtrusionLayer.setProperties(
fillExtrusionColor(Color.LTGRAY),
fillExtrusionHeight(Expression.get("height")),
fillExtrusionBase(Expression.get("min_height")),
fillExtrusionOpacity(0.9f)
);
style.addLayer(fillExtrusionLayer);
}
private void setupLight() {
light = mapboxMap.getStyle().getLight();
findViewById(R.id.fabLightPosition).setOnClickListener(v -> {
isInitPosition = !isInitPosition;
if (isInitPosition) {
light.setPosition(new Position(1.5f, 90, 80));
} else {
light.setPosition(new Position(1.15f, 210, 30));
}
});
findViewById(R.id.fabLightColor).setOnClickListener(v -> {
isRedColor = !isRedColor;
light.setColor(ColorUtils.colorToRgbaString(isRedColor ? Color.RED : Color.BLUE));
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_building, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (light != null) {
int id = item.getItemId();
if (id == R.id.menu_action_anchor) {
isMapAnchorLight = !isMapAnchorLight;
light.setAnchor(isMapAnchorLight ? Property.ANCHOR_MAP : Property.ANCHOR_VIEWPORT);
} else if (id == R.id.menu_action_intensity) {
isLowIntensityLight = !isLowIntensityLight;
light.setIntensity(isLowIntensityLight ? 0.35f : 1.0f);
}
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
public void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
}

View File

@@ -0,0 +1,284 @@
package com.mapbox.mapboxsdk.testapp.activity.style;
import android.graphics.Color;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.res.ResourcesCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.style.expressions.Expression;
import com.mapbox.mapboxsdk.style.layers.CircleLayer;
import com.mapbox.mapboxsdk.style.layers.SymbolLayer;
import com.mapbox.mapboxsdk.style.sources.GeoJsonOptions;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import com.mapbox.mapboxsdk.testapp.R;
import timber.log.Timber;
import java.net.URI;
import java.net.URISyntaxException;
import static com.mapbox.mapboxsdk.style.expressions.Expression.all;
import static com.mapbox.mapboxsdk.style.expressions.Expression.get;
import static com.mapbox.mapboxsdk.style.expressions.Expression.gt;
import static com.mapbox.mapboxsdk.style.expressions.Expression.gte;
import static com.mapbox.mapboxsdk.style.expressions.Expression.has;
import static com.mapbox.mapboxsdk.style.expressions.Expression.literal;
import static com.mapbox.mapboxsdk.style.expressions.Expression.lt;
import static com.mapbox.mapboxsdk.style.expressions.Expression.toNumber;
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.iconImage;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textAllowOverlap;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textField;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textIgnorePlacement;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textSize;
/**
* Test activity showcasing adding a Circle Layer to the Map
* <p>
* Uses bus stop data from Singapore as a source and allows to filter into 1 specific route with a line layer.
* </p>
*/
public class CircleLayerActivity extends AppCompatActivity implements View.OnClickListener {
public static final String SOURCE_ID = "bus_stop";
public static final String SOURCE_ID_CLUSTER = "bus_stop_cluster";
public static final String URL_BUS_ROUTES = "https://raw.githubusercontent.com/cheeaun/busrouter-sg/master/data/2/bus-stops.geojson";
public static final String LAYER_ID = "stops_layer";
private MapView mapView;
private MapboxMap mapboxMap;
private FloatingActionButton styleFab;
private FloatingActionButton routeFab;
private CircleLayer layer;
private GeoJsonSource source;
private int currentStyleIndex = 0;
private boolean isLoadingStyle = true;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_circle_layer);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(map -> {
mapboxMap = map;
mapboxMap.setStyle(Style.SATELLITE_STREETS);
mapView.addOnDidFinishLoadingStyleListener(() -> {
Style style = mapboxMap.getStyle();
addBusStopSource(style);
addBusStopCircleLayer(style);
initFloatingActionButtons();
isLoadingStyle = false;
});
});
}
private void addBusStopSource(Style style) {
try {
source = new GeoJsonSource(SOURCE_ID, new URI(URL_BUS_ROUTES));
} catch (URISyntaxException exception) {
Timber.e(exception, "That's not an url... ");
}
style.addSource(source);
}
private void addBusStopCircleLayer(Style style) {
layer = new CircleLayer(LAYER_ID, SOURCE_ID);
layer.setProperties(
circleColor(Color.parseColor("#FF9800")),
circleRadius(2.0f)
);
style.addLayerBelow(layer, "waterway-label");
}
private void initFloatingActionButtons() {
routeFab = findViewById(R.id.fab_route);
routeFab.setColorFilter(ContextCompat.getColor(CircleLayerActivity.this, R.color.primary));
routeFab.setOnClickListener(CircleLayerActivity.this);
styleFab = findViewById(R.id.fab_style);
styleFab.setOnClickListener(CircleLayerActivity.this);
}
@Override
public void onClick(View view) {
if (isLoadingStyle) {
return;
}
if (view.getId() == R.id.fab_route) {
showBusCluster();
} else if (view.getId() == R.id.fab_style) {
changeMapStyle();
}
}
private void showBusCluster() {
removeFabs();
removeOldSource();
addClusteredSource();
}
private void removeOldSource() {
mapboxMap.getStyle().removeSource(SOURCE_ID);
mapboxMap.getStyle().removeLayer(LAYER_ID);
}
private void addClusteredSource() {
try {
mapboxMap.getStyle().addSource(
new GeoJsonSource(SOURCE_ID_CLUSTER,
new URI(URL_BUS_ROUTES),
new GeoJsonOptions()
.withCluster(true)
.withClusterMaxZoom(14)
.withClusterRadius(50)
)
);
} catch (URISyntaxException malformedUrlException) {
Timber.e(malformedUrlException, "That's not an url... ");
}
// Add unclustered layer
int[][] layers = new int[][] {
new int[] {150, ResourcesCompat.getColor(getResources(), R.color.redAccent, getTheme())},
new int[] {20, ResourcesCompat.getColor(getResources(), R.color.greenAccent, getTheme())},
new int[] {0, ResourcesCompat.getColor(getResources(), R.color.blueAccent, getTheme())}
};
SymbolLayer unclustered = new SymbolLayer("unclustered-points", SOURCE_ID_CLUSTER);
unclustered.setProperties(
iconImage("bus-15")
);
mapboxMap.getStyle().addLayer(unclustered);
for (int i = 0; i < layers.length; i++) {
// Add some nice circles
CircleLayer circles = new CircleLayer("cluster-" + i, SOURCE_ID_CLUSTER);
circles.setProperties(
circleColor(layers[i][1]),
circleRadius(18f)
);
Expression pointCount = toNumber(get("point_count"));
circles.setFilter(
i == 0
? all(has("point_count"),
gte(pointCount, literal(layers[i][0]))
) : all(has("point_count"),
gt(pointCount, literal(layers[i][0])),
lt(pointCount, literal(layers[i - 1][0]))
)
);
mapboxMap.getStyle().addLayer(circles);
}
// Add the count labels
SymbolLayer count = new SymbolLayer("count", SOURCE_ID_CLUSTER);
count.setProperties(
textField(Expression.toString(get("point_count"))),
textSize(12f),
textColor(Color.WHITE),
textIgnorePlacement(true),
textAllowOverlap(true)
);
mapboxMap.getStyle().addLayer(count);
}
private void removeFabs() {
routeFab.setVisibility(View.GONE);
styleFab.setVisibility(View.GONE);
}
private void changeMapStyle() {
isLoadingStyle = true;
removeBusStop();
loadNewStyle();
}
private void removeBusStop() {
mapboxMap.getStyle().removeLayer(layer);
mapboxMap.getStyle().removeSource(source);
}
private void loadNewStyle() {
mapboxMap.setStyle(new Style.Builder().fromUri(getNextStyle()));
}
private void addBusStop() {
mapboxMap.getStyle().addLayer(layer);
mapboxMap.getStyle().addSource(source);
}
private String getNextStyle() {
currentStyleIndex++;
if (currentStyleIndex == Data.STYLES.length) {
currentStyleIndex = 0;
}
return Data.STYLES[currentStyleIndex];
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
public void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
private static class Data {
private static final String[] STYLES = new String[] {
Style.MAPBOX_STREETS,
Style.OUTDOORS,
Style.LIGHT,
Style.DARK,
Style.SATELLITE,
Style.SATELLITE_STREETS
};
}
}

View File

@@ -0,0 +1,144 @@
package com.mapbox.mapboxsdk.testapp.activity.style;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import com.mapbox.geojson.Feature;
import com.mapbox.geojson.FeatureCollection;
import com.mapbox.geojson.Point;
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.Style;
import com.mapbox.mapboxsdk.style.layers.Layer;
import com.mapbox.mapboxsdk.style.layers.SymbolLayer;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import com.mapbox.mapboxsdk.testapp.R;
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;
/**
* Test activity showcasing adding a sprite image and use it in a Symbol Layer
*/
public class CustomSpriteActivity extends AppCompatActivity {
private static final String CUSTOM_ICON = "custom-icon";
private GeoJsonSource source;
private MapboxMap mapboxMap;
private MapView mapView;
private Layer layer;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_sprite);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(map -> {
mapboxMap = map;
map.setStyle(Style.MAPBOX_STREETS, style -> {
final FloatingActionButton fab = findViewById(R.id.fab);
fab.setColorFilter(ContextCompat.getColor(CustomSpriteActivity.this, R.color.primary));
fab.setOnClickListener(new View.OnClickListener() {
private Point point;
@Override
public void onClick(View view) {
if (point == null) {
Timber.i("First click -> Car");
// Add an icon to reference later
style.addImage(CUSTOM_ICON, BitmapFactory.decodeResource(getResources(), R.drawable.ic_car_top));
// Add a source with a geojson point
point = Point.fromLngLat(13.400972d, 52.519003d);
source = new GeoJsonSource(
"point",
FeatureCollection.fromFeatures(new Feature[] {Feature.fromGeometry(point)})
);
mapboxMap.getStyle().addSource(source);
// Add a symbol layer that references that point source
layer = new SymbolLayer("layer", "point");
layer.setProperties(
// Set the id of the sprite to use
iconImage(CUSTOM_ICON),
iconAllowOverlap(true),
iconIgnorePlacement(true)
);
// lets add a circle below labels!
mapboxMap.getStyle().addLayerBelow(layer, "waterway-label");
fab.setImageResource(R.drawable.ic_directions_car_black);
} else {
// Update point
point = Point.fromLngLat(point.longitude() + 0.001,
point.latitude() + 0.001);
source.setGeoJson(FeatureCollection.fromFeatures(new Feature[] {Feature.fromGeometry(point)}));
// Move the camera as well
mapboxMap.moveCamera(CameraUpdateFactory.newLatLng(new LatLng(
point.latitude(), point.longitude())));
}
}
});
});
});
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
public void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
}

View File

@@ -0,0 +1,472 @@
package com.mapbox.mapboxsdk.testapp.activity.style;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;
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.Style;
import com.mapbox.mapboxsdk.style.layers.FillLayer;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import com.mapbox.mapboxsdk.style.sources.Source;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.utils.IdleZoomListener;
import com.mapbox.mapboxsdk.testapp.utils.ResourceUtils;
import java.io.IOException;
import timber.log.Timber;
import static com.mapbox.mapboxsdk.style.expressions.Expression.exponential;
import static com.mapbox.mapboxsdk.style.expressions.Expression.get;
import static com.mapbox.mapboxsdk.style.expressions.Expression.interpolate;
import static com.mapbox.mapboxsdk.style.expressions.Expression.linear;
import static com.mapbox.mapboxsdk.style.expressions.Expression.literal;
import static com.mapbox.mapboxsdk.style.expressions.Expression.match;
import static com.mapbox.mapboxsdk.style.expressions.Expression.rgb;
import static com.mapbox.mapboxsdk.style.expressions.Expression.rgba;
import static com.mapbox.mapboxsdk.style.expressions.Expression.step;
import static com.mapbox.mapboxsdk.style.expressions.Expression.stop;
import static com.mapbox.mapboxsdk.style.expressions.Expression.zoom;
import static com.mapbox.mapboxsdk.style.expressions.Expression.color;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillAntialias;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillOpacity;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillOutlineColor;
/**
* Test activity showcasing the data driven runtime style API.
*/
public class DataDrivenStyleActivity extends AppCompatActivity {
public static final String AMSTERDAM_PARKS_LAYER = "amsterdam-parks-layer";
private MapView mapView;
private MapboxMap mapboxMap;
private IdleZoomListener idleListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_data_driven_style);
// Initialize map as normal
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(map -> {
// Store for later
mapboxMap = map;
mapboxMap.setStyle(Style.MAPBOX_STREETS, style -> {
// Add a parks layer
addParksLayer();
// Add debug overlay
setupDebugZoomView();
});
// Center and Zoom (Amsterdam, zoomed to streets)
mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(52.379189, 4.899431), 14));
});
}
private void setupDebugZoomView() {
final TextView textView = (TextView) findViewById(R.id.textZoom);
mapboxMap.addOnCameraIdleListener(idleListener = new IdleZoomListener(mapboxMap, textView));
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_data_driven_style, menu);
return true;
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
if (mapboxMap != null && idleListener != null) {
mapboxMap.removeOnCameraIdleListener(idleListener);
}
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_add_exponential_zoom_function:
addExponentialZoomFunction();
return true;
case R.id.action_add_interval_zoom_function:
addIntervalZoomFunction();
return true;
case R.id.action_add_categorical_source_function:
addCategoricalSourceFunction();
return true;
case R.id.action_add_exponential_source_function:
addExponentialSourceFunction();
return true;
case R.id.action_add_identity_source_function:
addIdentitySourceFunction();
return true;
case R.id.action_add_interval_source_function:
addIntervalSourceFunction();
return true;
case R.id.action_add_composite_categorical_function:
addCompositeCategoricalFunction();
return true;
case R.id.action_add_composite_exponential_function:
addCompositeExponentialFunction();
return true;
case R.id.action_add_composite_interval_function:
addCompositeIntervalFunction();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void addExponentialZoomFunction() {
Timber.i("Add exponential zoom function");
FillLayer layer = mapboxMap.getStyle().getLayerAs("water");
assert layer != null;
layer.setProperties(
fillColor(
interpolate(
exponential(0.5f), zoom(),
stop(1, color(Color.RED)),
stop(5, color(Color.BLUE)),
stop(10, color(Color.GREEN))
)
)
);
Timber.i("Fill color: %s", layer.getFillColor());
}
private void addIntervalZoomFunction() {
Timber.i("Add interval zoom function");
FillLayer layer = mapboxMap.getStyle().getLayerAs("water");
assert layer != null;
layer.setProperties(
fillColor(
step(zoom(),
rgba(0.0f, 255.0f, 255.0f, 1.0f),
stop(1, rgba(255.0f, 0.0f, 0.0f, 1.0f)),
stop(5, rgba(0.0f, 0.0f, 255.0f, 1.0f)),
stop(10, rgba(0.0f, 255.0f, 0.0f, 1.0f))
)
)
);
Timber.i("Fill color: %s", layer.getFillColor());
}
private void addExponentialSourceFunction() {
Timber.i("Add exponential source function");
FillLayer layer = mapboxMap.getStyle().getLayerAs(AMSTERDAM_PARKS_LAYER);
assert layer != null;
layer.setProperties(
fillColor(
interpolate(
exponential(0.5f),
get("stroke-width"),
stop(1f, rgba(255.0f, 0.0f, 0.0f, 1.0f)),
stop(5f, rgba(0.0f, 0.0f, 255.0f, 1.0f)),
stop(10f, rgba(0.0f, 255.0f, 0.0f, 1.0f))
)
)
);
Timber.i("Fill color: %s", layer.getFillColor());
}
private void addCategoricalSourceFunction() {
Timber.i("Add categorical source function");
FillLayer layer = mapboxMap.getStyle().getLayerAs(AMSTERDAM_PARKS_LAYER);
assert layer != null;
layer.setProperties(
fillColor(
match(
get("name"),
literal("Westerpark"), rgba(255.0f, 0.0f, 0.0f, 1.0f),
literal("Jordaan"), rgba(0.0f, 0.0f, 255.0f, 1.0f),
literal("Prinseneiland"), rgba(0.0f, 255.0f, 0.0f, 1.0f),
rgba(0.0f, 255.0f, 255.0f, 1.0f)
)
)
);
Timber.i("Fill color: %s", layer.getFillColor());
}
private void addIdentitySourceFunction() {
Timber.i("Add identity source function");
FillLayer layer = mapboxMap.getStyle().getLayerAs(AMSTERDAM_PARKS_LAYER);
assert layer != null;
layer.setProperties(
fillOpacity(
get("fill-opacity")
)
);
Timber.i("Fill opacity: %s", layer.getFillOpacity());
}
private void addIntervalSourceFunction() {
Timber.i("Add interval source function");
FillLayer layer = mapboxMap.getStyle().getLayerAs(AMSTERDAM_PARKS_LAYER);
assert layer != null;
layer.setProperties(
fillColor(
step(
get("stroke-width"),
rgba(0.0f, 255.0f, 255.0f, 1.0f),
stop(1f, rgba(255.0f, 0.0f, 0.0f, 1.0f)),
stop(2f, rgba(0.0f, 0.0f, 255.0f, 1.0f)),
stop(3f, rgba(0.0f, 255.0f, 0.0f, 1.0f))
)
)
);
Timber.i("Fill color: %s", layer.getFillColor());
}
private void addCompositeExponentialFunction() {
Timber.i("Add composite exponential function");
FillLayer layer = mapboxMap.getStyle().getLayerAs(AMSTERDAM_PARKS_LAYER);
assert layer != null;
layer.setProperties(
fillColor(
interpolate(
exponential(1f),
zoom(),
stop(12, step(
get("stroke-width"),
rgba(255.0f, 255.0f, 255.0f, 1.0f),
stop(1f, rgba(255.0f, 0.0f, 0.0f, 1.0f)),
stop(2f, rgba(0.0f, 0.0f, 0.0f, 1.0f)),
stop(3f, rgba(0.0f, 0.0f, 255.0f, 1.0f))
)),
stop(15, step(
get("stroke-width"),
rgba(255.0f, 255.0f, 255.0f, 1.0f),
stop(1f, rgba(255.0f, 255.0f, 0.0f, 1.0f)),
stop(2f, rgba(211.0f, 211.0f, 211.0f, 1.0f)),
stop(3f, rgba(0.0f, 255.0f, 255.0f, 1.0f))
)),
stop(18, step(
get("stroke-width"),
rgba(255.0f, 255.0f, 255.0f, 1.0f),
stop(1f, rgba(0.0f, 0.0f, 0.0f, 1.0f)),
stop(2f, rgba(128.0f, 128.0f, 128.0f, 1.0f)),
stop(3f, rgba(0.0f, 255.0f, 0.0f, 1.0f)))
)
)
)
);
Timber.i("Fill color: %s", layer.getFillColor());
}
private void addCompositeIntervalFunction() {
Timber.i("Add composite interval function");
FillLayer layer = mapboxMap.getStyle().getLayerAs(AMSTERDAM_PARKS_LAYER);
assert layer != null;
layer.setProperties(
fillColor(
interpolate(
linear(),
zoom(),
stop(12, step(
get("stroke-width"),
rgba(255.0f, 255.0f, 255.0f, 1.0f),
stop(1f, rgba(255.0f, 0.0f, 0.0f, 1.0f)),
stop(2f, rgba(0.0f, 0.0f, 0.0f, 1.0f)),
stop(3f, rgba(0.0f, 0.0f, 255.0f, 1.0f))
)),
stop(15, step(
get("stroke-width"),
rgba(255.0f, 255.0f, 255.0f, 1.0f),
stop(1f, rgba(255.0f, 255.0f, 0.0f, 1.0f)),
stop(2f, rgba(211.0f, 211.0f, 211.0f, 1.0f)),
stop(3f, rgba(0.0f, 255.0f, 255.0f, 1.0f))
)),
stop(18, step(
get("stroke-width"),
rgba(255.0f, 255.0f, 255.0f, 1.0f),
stop(1f, rgba(0.0f, 0.0f, 0.0f, 1.0f)),
stop(2f, rgba(128.0f, 128.0f, 128.0f, 1.0f)),
stop(3f, rgba(0.0f, 255.0f, 0.0f, 1.0f))
))
)
)
);
Timber.i("Fill color: %s", layer.getFillColor());
}
private void addCompositeCategoricalFunction() {
Timber.i("Add composite categorical function");
FillLayer layer = mapboxMap.getStyle().getLayerAs(AMSTERDAM_PARKS_LAYER);
assert layer != null;
layer.setProperties(
fillColor(
step(zoom(),
rgba(255.0f, 255.0f, 255.0f, 1.0f),
stop(7f, match(
get("name"),
literal("Westerpark"), rgba(255.0f, 0.0f, 0.0f, 1.0f),
rgba(255.0f, 255.0f, 255.0f, 1.0f)
)),
stop(8f, match(
get("name"),
literal("Westerpark"), rgba(0.0f, 0.0f, 255.0f, 1.0f),
rgba(255.0f, 255.0f, 255.0f, 1.0f)
)),
stop(9f, match(
get("name"),
literal("Westerpark"), rgba(255.0f, 0.0f, 0.0f, 1.0f),
rgba(255.0f, 255.0f, 255.0f, 1.0f)
)),
stop(10f, match(
get("name"),
literal("Westerpark"), rgba(0.0f, 0.0f, 255.0f, 1.0f),
rgba(255.0f, 255.0f, 255.0f, 1.0f)
)),
stop(11f, match(
get("name"),
literal("Westerpark"), rgba(255.0f, 0.0f, 0.0f, 1.0f),
rgba(255.0f, 255.0f, 255.0f, 1.0f)
)),
stop(12f, match(
get("name"),
literal("Westerpark"), rgba(0.0f, 0.0f, 255.0f, 1.0f),
rgba(255.0f, 255.0f, 255.0f, 1.0f)
)),
stop(13f, match(
get("name"),
literal("Westerpark"), rgba(255.0f, 0.0f, 0.0f, 1.0f),
rgba(255.0f, 255.0f, 255.0f, 1.0f)
)),
stop(14f, match(
get("name"),
literal("Westerpark"), rgba(0.0f, 0.0f, 255.0f, 1.0f),
literal("Jordaan"), rgba(0.0f, 255.0f, 0.0f, 1.0f),
literal("PrinsenEiland"), rgba(0.0f, 0.0f, 0.0f, 1.0f),
rgba(255.0f, 255.0f, 255.0f, 1.0f)
)),
stop(15f, match(
get("name"),
literal("Westerpark"), rgba(255.0f, 0.0f, 0.0f, 1.0f),
rgba(255.0f, 255.0f, 255.0f, 1.0f)
)),
stop(16f, match(
get("name"),
literal("Westerpark"), rgba(0.0f, 0.0f, 255.0f, 1.0f),
rgba(255.0f, 255.0f, 255.0f, 1.0f)
)),
stop(17f, match(
get("name"),
literal("Westerpark"), rgba(255.0f, 0.0f, 0.0f, 1.0f),
rgba(255.0f, 255.0f, 255.0f, 1.0f)
)),
stop(18f, match(
get("name"),
literal("Westerpark"), rgba(0.0f, 0.0f, 255.0f, 1.0f),
literal("Jordaan"), rgba(0.0f, 255.0f, 255.0f, 1.0f),
rgba(255.0f, 255.0f, 255.0f, 1.0f)
)),
stop(19f, match(
get("name"),
literal("Westerpark"), rgba(255.0f, 0.0f, 0.0f, 1.0f),
rgba(255.0f, 255.0f, 255.0f, 1.0f)
)),
stop(20f, match(
get("name"),
literal("Westerpark"), rgba(0.0f, 0.0f, 255.0f, 1.0f),
rgba(255.0f, 255.0f, 255.0f, 1.0f)
)),
stop(21f, match(
get("name"),
literal("Westerpark"), rgba(255.0f, 0.0f, 0.0f, 1.0f),
rgba(255.0f, 255.0f, 255.0f, 1.0f)
)),
stop(22f, match(
get("name"),
literal("Westerpark"), rgba(0.0f, 0.0f, 255.0f, 1.0f),
rgba(255.0f, 255.0f, 255.0f, 1.0f)
))
)
)
);
Timber.i("Fill color: %s", layer.getFillColor());
}
private void addParksLayer() {
// Add a source
Source source;
try {
source = new GeoJsonSource("amsterdam-parks-source", ResourceUtils.readRawResource(this, R.raw.amsterdam));
mapboxMap.getStyle().addSource(source);
} catch (IOException ioException) {
Toast.makeText(
DataDrivenStyleActivity.this,
"Couldn't add source: " + ioException.getMessage(),
Toast.LENGTH_SHORT).show();
return;
}
// Add a fill layer
mapboxMap.getStyle().addLayer(new FillLayer(AMSTERDAM_PARKS_LAYER, source.getId())
.withProperties(
fillColor(color(Color.GREEN)),
fillOutlineColor(rgb(0, 0, 255)),
fillAntialias(true)
)
);
}
}

View File

@@ -0,0 +1,331 @@
package com.mapbox.mapboxsdk.testapp.activity.style
import android.graphics.PointF
import android.os.Bundle
import android.support.design.widget.Snackbar
import android.support.v7.app.AppCompatActivity
import android.view.MotionEvent
import android.view.View
import com.mapbox.android.gestures.AndroidGesturesManager
import com.mapbox.android.gestures.MoveGestureDetector
import com.mapbox.geojson.Feature
import com.mapbox.geojson.FeatureCollection
import com.mapbox.geojson.Point
import com.mapbox.mapboxsdk.annotations.IconFactory
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.Style
import com.mapbox.mapboxsdk.style.layers.PropertyFactory.*
import com.mapbox.mapboxsdk.style.layers.SymbolLayer
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource
import com.mapbox.mapboxsdk.testapp.R
import kotlinx.android.synthetic.main.activity_draggable_marker.*
/**
* An Activity that showcases how to make symbols draggable.
*/
class DraggableMarkerActivity : AppCompatActivity() {
companion object {
private const val sourceId = "source_draggable"
private const val layerId = "layer_draggable"
private const val markerImageId = "marker_icon_draggable"
private var latestId: Long = 0
fun generateMarkerId(): String {
if (latestId == Long.MAX_VALUE) {
throw RuntimeException("You've added too many markers.")
}
return latestId++.toString()
}
}
private val actionBarHeight: Int by lazy {
supportActionBar?.height ?: 0
}
// View property is required for activity sanity tests
// we perform reflection on this requires using findViewById
private lateinit var mapView: MapView
private lateinit var mapboxMap: MapboxMap
private val featureCollection = FeatureCollection.fromFeatures(mutableListOf())
private val source = GeoJsonSource(sourceId, featureCollection)
private val layer = SymbolLayer(layerId, sourceId)
.withProperties(
iconImage(markerImageId),
iconAllowOverlap(true),
iconIgnorePlacement(true))
private var draggableSymbolsManager: DraggableSymbolsManager? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_draggable_marker)
mapView = findViewById(R.id.mapView)
mapView.onCreate(savedInstanceState)
mapView.getMapAsync { mapboxMap ->
this.mapboxMap = mapboxMap
mapboxMap.setStyle(
Style.Builder()
.fromUri(Style.MAPBOX_STREETS)
.withImage(markerImageId, IconFactory.getInstance(this).defaultMarker().bitmap)
.withSource(source)
.withLayer(layer)
)
// Add initial markers
addMarker(LatLng(52.407210, 16.924324))
addMarker(LatLng(41.382679, 2.181555))
addMarker(LatLng(51.514886, -0.112589))
// Initial camera position
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(
LatLng(45.0, 8.0), 3.0
))
mapboxMap.addOnMapClickListener {
// Adding a marker on map click
val features = mapboxMap.queryRenderedSymbols(it, layerId)
if (features.isEmpty()) {
addMarker(it)
} else {
// Displaying marker info on marker click
Snackbar.make(
mapView,
"Marker's position: %.4f, %.4f".format(it.latitude, it.longitude),
Snackbar.LENGTH_LONG)
.show()
}
false
}
draggableSymbolsManager = DraggableSymbolsManager(
mapView, mapboxMap, featureCollection, source, layerId, actionBarHeight, 0)
// Adding symbol drag listeners
draggableSymbolsManager?.addOnSymbolDragListener(object : DraggableSymbolsManager.OnSymbolDragListener {
override fun onSymbolDragStarted(id: String) {
draggedMarkerPositionTv.visibility = View.VISIBLE
Snackbar.make(
mapView,
"Marker drag started (%s)".format(id),
Snackbar.LENGTH_SHORT)
.show()
}
override fun onSymbolDrag(id: String) {
val point = featureCollection.features()?.find {
it.id() == id
}?.geometry() as Point
draggedMarkerPositionTv.text = "Dragged marker's position: %.4f, %.4f".format(point.latitude(), point.longitude())
}
override fun onSymbolDragFinished(id: String) {
draggedMarkerPositionTv.visibility = View.GONE
Snackbar.make(
mapView,
"Marker drag finished (%s)".format(id),
Snackbar.LENGTH_SHORT)
.show()
}
})
}
}
private fun addMarker(latLng: LatLng) {
featureCollection.features()?.add(
Feature.fromGeometry(Point.fromLngLat(latLng.longitude, latLng.latitude), null, generateMarkerId()))
source.setGeoJson(featureCollection)
}
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
// Dispatching parent's touch events to the manager
draggableSymbolsManager?.onParentTouchEvent(ev)
return super.dispatchTouchEvent(ev)
}
/**
* A manager, that allows dragging symbols after they are long clicked.
* Since this manager lives outside of the Maps SDK, we need to intercept parent's motion events
* and pass them with [DraggableSymbolsManager.onParentTouchEvent].
* If we were to try and overwrite [AppCompatActivity.onTouchEvent], those events would've been
* consumed by the map.
*
* We also need to setup a [DraggableSymbolsManager.androidGesturesManager],
* because after disabling map's gestures and starting the drag process
* we still need to listen for move gesture events which map won't be able to provide anymore.
*
* @param mapView the mapView
* @param mapboxMap the mapboxMap
* @param symbolsCollection the collection that contains all the symbols that we want to be draggable
* @param symbolsSource the source that contains the [symbolsCollection]
* @param symbolsLayerId the ID of the layer that the symbols are displayed on
* @param touchAreaShiftX X-axis padding that is applied to the parent's window motion event,
* as that window can be bigger than the [mapView].
* @param touchAreaShiftY Y-axis padding that is applied to the parent's window motion event,
* as that window can be bigger than the [mapView].
* @param touchAreaMaxX maximum value of X-axis motion event
* @param touchAreaMaxY maximum value of Y-axis motion event
*/
class DraggableSymbolsManager(
mapView: MapView,
private val mapboxMap: MapboxMap,
private val symbolsCollection: FeatureCollection,
private val symbolsSource: GeoJsonSource,
private val symbolsLayerId: String,
private val touchAreaShiftY: Int = 0,
private val touchAreaShiftX: Int = 0,
private val touchAreaMaxX: Int = mapView.width,
private val touchAreaMaxY: Int = mapView.height
) {
private val androidGesturesManager: AndroidGesturesManager = AndroidGesturesManager(mapView.context, false)
private var draggedSymbolId: String? = null
private val onSymbolDragListeners: MutableList<OnSymbolDragListener> = mutableListOf<OnSymbolDragListener>()
init {
mapboxMap.addOnMapLongClickListener {
// Starting the drag process on long click
draggedSymbolId = mapboxMap.queryRenderedSymbols(it, symbolsLayerId).firstOrNull()?.id()?.also { id ->
mapboxMap.uiSettings.setAllGesturesEnabled(false)
mapboxMap.gesturesManager.moveGestureDetector.interrupt()
notifyOnSymbolDragListeners {
onSymbolDragStarted(id)
}
}
false
}
androidGesturesManager.setMoveGestureListener(MyMoveGestureListener())
}
inner class MyMoveGestureListener : MoveGestureDetector.OnMoveGestureListener {
override fun onMoveBegin(detector: MoveGestureDetector): Boolean {
return true
}
override fun onMove(detector: MoveGestureDetector, distanceX: Float, distanceY: Float): Boolean {
if (detector.pointersCount > 1) {
// Stopping the drag when we don't work with a simple, on-pointer move anymore
stopDragging()
return true
}
// Updating symbol's position
draggedSymbolId?.also { draggedSymbolId ->
val moveObject = detector.getMoveObject(0)
val point = PointF(moveObject.currentX - touchAreaShiftX, moveObject.currentY - touchAreaShiftY)
if (point.x < 0 || point.y < 0 || point.x > touchAreaMaxX || point.y > touchAreaMaxY) {
stopDragging()
}
val latLng = mapboxMap.projection.fromScreenLocation(point)
symbolsCollection.features()?.indexOfFirst {
it.id() == draggedSymbolId
}?.also { index ->
symbolsCollection.features()?.get(index)?.also { oldFeature ->
val properties = oldFeature.properties()
val newFeature = Feature.fromGeometry(
Point.fromLngLat(latLng.longitude, latLng.latitude),
properties,
draggedSymbolId
)
symbolsCollection.features()?.set(index, newFeature)
symbolsSource.setGeoJson(symbolsCollection)
notifyOnSymbolDragListeners {
onSymbolDrag(draggedSymbolId)
}
return true
}
}
}
return false
}
override fun onMoveEnd(detector: MoveGestureDetector, velocityX: Float, velocityY: Float) {
// Stopping the drag when move ends
stopDragging()
}
}
private fun stopDragging() {
mapboxMap.uiSettings.setAllGesturesEnabled(true)
draggedSymbolId?.let {
notifyOnSymbolDragListeners {
onSymbolDragFinished(it)
}
}
draggedSymbolId = null
}
fun onParentTouchEvent(ev: MotionEvent?) {
androidGesturesManager.onTouchEvent(ev)
}
private fun notifyOnSymbolDragListeners(action: OnSymbolDragListener.() -> Unit) {
onSymbolDragListeners.forEach(action)
}
fun addOnSymbolDragListener(listener: OnSymbolDragListener) {
onSymbolDragListeners.add(listener)
}
fun removeOnSymbolDragListener(listener: OnSymbolDragListener) {
onSymbolDragListeners.remove(listener)
}
interface OnSymbolDragListener {
fun onSymbolDragStarted(id: String)
fun onSymbolDrag(id: String)
fun onSymbolDragFinished(id: String)
}
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
override fun onDestroy() {
super.onDestroy()
mapView.onDestroy()
}
override fun onSaveInstanceState(outState: Bundle?) {
super.onSaveInstanceState(outState)
outState?.let {
mapView.onSaveInstanceState(it)
}
}
}
private fun MapboxMap.queryRenderedSymbols(latLng: LatLng, layerId: String): List<Feature> {
return this.queryRenderedFeatures(this.projection.toScreenLocation(latLng), layerId)
}

View File

@@ -0,0 +1,122 @@
package com.mapbox.mapboxsdk.testapp.activity.style;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.mapbox.geojson.Point;
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.Style;
import com.mapbox.mapboxsdk.style.layers.FillExtrusionLayer;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.geojson.Polygon;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionHeight;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillExtrusionOpacity;
/**
* Test activity showcasing fill extrusions
*/
public class FillExtrusionActivity extends AppCompatActivity {
private MapView mapView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fill_extrusion_layer);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(mapboxMap -> {
mapboxMap.setStyle(Style.MAPBOX_STREETS, style -> {
List<List<Point>> lngLats = Collections.singletonList(
Arrays.asList(
Point.fromLngLat(5.12112557888031, 52.09071040847704),
Point.fromLngLat(5.121227502822875, 52.09053901776669),
Point.fromLngLat(5.121484994888306, 52.090601641371805),
Point.fromLngLat(5.1213884353637695, 52.090766439912635),
Point.fromLngLat(5.12112557888031, 52.09071040847704)
)
);
Polygon domTower = Polygon.fromLngLats(lngLats);
GeoJsonSource source = new GeoJsonSource("extrusion-source", domTower);
style.addSource(source);
style.addLayer(
new FillExtrusionLayer("extrusion-layer", source.getId())
.withProperties(
fillExtrusionHeight(40f),
fillExtrusionOpacity(0.5f),
fillExtrusionColor(Color.RED)
)
);
mapboxMap.animateCamera(
CameraUpdateFactory.newCameraPosition(
new CameraPosition.Builder()
.target(new LatLng(52.09071040847704, 5.12112557888031))
.tilt(45.0)
.zoom(18)
.build()
),
10000
);
});
});
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
public void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
}

View File

@@ -0,0 +1,78 @@
package com.mapbox.mapboxsdk.testapp.activity.style;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.testapp.R;
/**
* Test activity used for instrumentation tests of fill extrusion.
*/
public class FillExtrusionStyleTestActivity extends AppCompatActivity {
public MapView mapView;
private MapboxMap mapboxMap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_extrusion_test);
// Initialize map as normal
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(mapboxMap ->
mapboxMap.setStyle(new Style.Builder().fromUri(Style.MAPBOX_STREETS),
style -> FillExtrusionStyleTestActivity.this.mapboxMap = mapboxMap
)
);
}
public MapboxMap getMapboxMap() {
return mapboxMap;
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}

View File

@@ -0,0 +1,281 @@
package com.mapbox.mapboxsdk.testapp.activity.style;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.PointF;
import android.os.Bundle;
import android.support.v4.content.res.ResourcesCompat;
import android.support.v7.app.AppCompatActivity;
import android.view.MenuItem;
import android.widget.Toast;
import com.mapbox.geojson.Feature;
import com.mapbox.geojson.FeatureCollection;
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.Style;
import com.mapbox.mapboxsdk.style.expressions.Expression;
import com.mapbox.mapboxsdk.style.layers.CircleLayer;
import com.mapbox.mapboxsdk.style.layers.SymbolLayer;
import com.mapbox.mapboxsdk.style.sources.GeoJsonOptions;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.utils.BitmapUtils;
import timber.log.Timber;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.Objects;
import static com.mapbox.mapboxsdk.style.expressions.Expression.all;
import static com.mapbox.mapboxsdk.style.expressions.Expression.accumulated;
import static com.mapbox.mapboxsdk.style.expressions.Expression.concat;
import static com.mapbox.mapboxsdk.style.expressions.Expression.division;
import static com.mapbox.mapboxsdk.style.expressions.Expression.exponential;
import static com.mapbox.mapboxsdk.style.expressions.Expression.get;
import static com.mapbox.mapboxsdk.style.expressions.Expression.gt;
import static com.mapbox.mapboxsdk.style.expressions.Expression.gte;
import static com.mapbox.mapboxsdk.style.expressions.Expression.has;
import static com.mapbox.mapboxsdk.style.expressions.Expression.interpolate;
import static com.mapbox.mapboxsdk.style.expressions.Expression.literal;
import static com.mapbox.mapboxsdk.style.expressions.Expression.lt;
import static com.mapbox.mapboxsdk.style.expressions.Expression.max;
import static com.mapbox.mapboxsdk.style.expressions.Expression.neq;
import static com.mapbox.mapboxsdk.style.expressions.Expression.rgb;
import static com.mapbox.mapboxsdk.style.expressions.Expression.stop;
import static com.mapbox.mapboxsdk.style.expressions.Expression.toNumber;
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.iconColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconSize;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textAllowOverlap;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textField;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textIgnorePlacement;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textSize;
/**
* Test activity showcasing using a geojson source and visualise that source as a cluster by using filters.
*/
public class GeoJsonClusteringActivity extends AppCompatActivity {
private static final double CAMERA_ZOOM_DELTA = 0.01;
private MapView mapView;
private MapboxMap mapboxMap;
private GeoJsonSource clusterSource;
private int clickOptionCounter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_geojson_clustering);
// Initialize map as normal
mapView = findViewById(R.id.mapView);
// noinspection ConstantConditions
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(map -> {
mapboxMap = map;
mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(37.7749, 122.4194), 0));
final int[][] clusterLayers = new int[][] {
new int[] {150, ResourcesCompat.getColor(getResources(), R.color.redAccent, getTheme())},
new int[] {20, ResourcesCompat.getColor(getResources(), R.color.greenAccent, getTheme())},
new int[] {0, ResourcesCompat.getColor(getResources(), R.color.blueAccent, getTheme())}
};
try {
mapboxMap.setStyle(new Style.Builder()
.fromUri(Style.LIGHT)
.withSource(clusterSource = createClusterSource())
.withLayer(createSymbolLayer())
.withLayer(createClusterLevelLayer(0, clusterLayers))
.withLayer(createClusterLevelLayer(1, clusterLayers))
.withLayer(createClusterLevelLayer(2, clusterLayers))
.withLayer(createClusterTextLayer())
.withImage("icon-id", Objects.requireNonNull(
BitmapUtils.getBitmapFromDrawable(getResources().getDrawable(R.drawable.ic_hearing_black_24dp))), true
)
);
} catch (URISyntaxException exception) {
Timber.e(exception);
}
mapboxMap.addOnMapClickListener(latLng -> {
PointF point = mapboxMap.getProjection().toScreenLocation(latLng);
List<Feature> features = mapboxMap.queryRenderedFeatures(point, "cluster-0", "cluster-1", "cluster-2");
if (!features.isEmpty()) {
onClusterClick(features.get(0), new Point((int) point.x, (int) point.y));
}
return true;
});
});
findViewById(R.id.fab).setOnClickListener(v -> {
updateClickOptionCounter();
notifyClickOptionUpdate();
});
}
private void onClusterClick(Feature cluster, Point clickPoint) {
if (clickOptionCounter == 0) {
double nextZoomLevel = clusterSource.getClusterExpansionZoom(cluster);
double zoomDelta = nextZoomLevel - mapboxMap.getCameraPosition().zoom;
mapboxMap.animateCamera(CameraUpdateFactory.zoomBy(zoomDelta + CAMERA_ZOOM_DELTA, clickPoint));
Toast.makeText(this, "Zooming to " + nextZoomLevel, Toast.LENGTH_SHORT).show();
} else if (clickOptionCounter == 1) {
FeatureCollection collection = clusterSource.getClusterChildren(cluster);
Toast.makeText(this, "Children: " + collection.toJson(), Toast.LENGTH_SHORT).show();
} else {
FeatureCollection collection = clusterSource.getClusterLeaves(cluster, 2, 1);
Toast.makeText(this, "Leaves: " + collection.toJson(), Toast.LENGTH_SHORT).show();
}
}
private GeoJsonSource createClusterSource() throws URISyntaxException {
return new GeoJsonSource("earthquakes", new URI("asset://earthquakes.geojson"), new GeoJsonOptions()
.withCluster(true)
.withClusterMaxZoom(14)
.withClusterRadius(50)
.withClusterProperty("max", max(accumulated(), get("max")), get("mag"))
.withClusterProperty("sum", literal("+"), get("mag"))
.withClusterProperty("felt", literal("any"), neq(get("felt"), literal("null")))
);
}
private SymbolLayer createSymbolLayer() {
return new SymbolLayer("unclustered-points", "earthquakes")
.withProperties(
iconImage("icon-id"),
iconSize(
division(
get("mag"), literal(4.0f)
)
),
iconColor(
interpolate(exponential(1), get("mag"),
stop(2.0, rgb(0, 255, 0)),
stop(4.5, rgb(0, 0, 255)),
stop(7.0, rgb(255, 0, 0))
)
)
)
.withFilter(has("mag"));
}
private CircleLayer createClusterLevelLayer(int level, int[][] layerColors) {
CircleLayer circles = new CircleLayer("cluster-" + level, "earthquakes");
circles.setProperties(
circleColor(layerColors[level][1]),
circleRadius(18f)
);
Expression pointCount = toNumber(get("point_count"));
circles.setFilter(
level == 0
? all(has("point_count"),
gte(pointCount, literal(layerColors[level][0]))
) : all(has("point_count"),
gt(pointCount, literal(layerColors[level][0])),
lt(pointCount, literal(layerColors[level - 1][0]))
)
);
return circles;
}
private SymbolLayer createClusterTextLayer() {
return new SymbolLayer("property", "earthquakes")
.withProperties(
textField(concat(get("point_count"), literal(", "), get("max"))),
textSize(12f),
textColor(Color.WHITE),
textIgnorePlacement(true),
textAllowOverlap(true)
);
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void updateClickOptionCounter() {
if (clickOptionCounter == 2) {
clickOptionCounter = 0;
} else {
clickOptionCounter++;
}
}
private void notifyClickOptionUpdate() {
if (clickOptionCounter == 0) {
Toast.makeText(
GeoJsonClusteringActivity.this,
"Clicking a cluster will zoom to the level where it dissolves",
Toast.LENGTH_SHORT).show();
} else if (clickOptionCounter == 1) {
Toast.makeText(
GeoJsonClusteringActivity.this,
"Clicking a cluster will show the details of the cluster children",
Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(
GeoJsonClusteringActivity.this,
"Clicking a cluster will show the details of the cluster leaves with an offset and limit",
Toast.LENGTH_SHORT).show();
}
}
}

View File

@@ -0,0 +1,117 @@
package com.mapbox.mapboxsdk.testapp.activity.style;
import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
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.LineLayer;
import com.mapbox.mapboxsdk.style.sources.GeoJsonOptions;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.utils.ResourceUtils;
import timber.log.Timber;
import java.io.IOException;
import static com.mapbox.mapboxsdk.style.expressions.Expression.interpolate;
import static com.mapbox.mapboxsdk.style.expressions.Expression.lineProgress;
import static com.mapbox.mapboxsdk.style.expressions.Expression.linear;
import static com.mapbox.mapboxsdk.style.expressions.Expression.rgb;
import static com.mapbox.mapboxsdk.style.expressions.Expression.stop;
import static com.mapbox.mapboxsdk.style.layers.Property.LINE_CAP_ROUND;
import static com.mapbox.mapboxsdk.style.layers.Property.LINE_JOIN_ROUND;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineCap;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineGradient;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineJoin;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineWidth;
/**
* Activity showcasing applying a gradient coloring to a line layer.
*/
public class GradientLineActivity extends AppCompatActivity implements OnMapReadyCallback {
public static final String LINE_SOURCE = "gradient";
private MapView mapView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gradient_line);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
}
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
try {
String geoJson = ResourceUtils.readRawResource(GradientLineActivity.this, R.raw.test_line_gradient_feature);
mapboxMap.setStyle(new Style.Builder()
.withSource(new GeoJsonSource(LINE_SOURCE, geoJson, new GeoJsonOptions().withLineMetrics(true)))
.withLayer(new LineLayer("gradient", LINE_SOURCE)
.withProperties(
lineGradient(interpolate(
linear(), lineProgress(),
stop(0f, rgb(0, 0, 255)),
stop(0.5f, rgb(0, 255, 0)),
stop(1f, rgb(255, 0, 0)))
),
lineColor(Color.RED),
lineWidth(10.0f),
lineCap(LINE_CAP_ROUND),
lineJoin(LINE_JOIN_ROUND)
))
);
} catch (IOException exception) {
Timber.e(exception);
}
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
public void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
}

View File

@@ -0,0 +1,154 @@
package com.mapbox.mapboxsdk.testapp.activity.style;
import android.graphics.Color;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import com.mapbox.geojson.Feature;
import com.mapbox.geojson.FeatureCollection;
import com.mapbox.geojson.MultiLineString;
import com.mapbox.geojson.Point;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
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.LineLayer;
import com.mapbox.mapboxsdk.style.sources.CustomGeometrySource;
import com.mapbox.mapboxsdk.style.sources.GeometryTileProvider;
import com.mapbox.mapboxsdk.testapp.R;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineColor;
/**
* Test activity showcasing using CustomGeometrySource to create a grid overlay on the map.
*/
public class GridSourceActivity extends AppCompatActivity implements OnMapReadyCallback {
public static final String ID_GRID_SOURCE = "grid_source";
public static final String ID_GRID_LAYER = "grid_layer";
private MapView mapView;
// public for testing purposes
public CustomGeometrySource source;
public LineLayer layer;
/**
* Implementation of GeometryTileProvider that returns features representing a zoom-dependent
* grid.
*/
static class GridProvider implements GeometryTileProvider {
public FeatureCollection getFeaturesForBounds(LatLngBounds bounds, int zoom) {
List<Feature> features = new ArrayList<>();
double gridSpacing;
if (zoom >= 13) {
gridSpacing = 0.01;
} else if (zoom >= 11) {
gridSpacing = 0.05;
} else if (zoom == 10) {
gridSpacing = .1;
} else if (zoom == 9) {
gridSpacing = 0.25;
} else if (zoom == 8) {
gridSpacing = 0.5;
} else if (zoom >= 6) {
gridSpacing = 1;
} else if (zoom == 5) {
gridSpacing = 2;
} else if (zoom >= 4) {
gridSpacing = 5;
} else if (zoom == 2) {
gridSpacing = 10;
} else {
gridSpacing = 20;
}
List gridLines = new ArrayList();
for (double y = Math.ceil(bounds.getLatNorth() / gridSpacing) * gridSpacing;
y >= Math.floor(bounds.getLatSouth() / gridSpacing) * gridSpacing; y -= gridSpacing) {
gridLines.add(Arrays.asList(Point.fromLngLat(bounds.getLonWest(), y),
Point.fromLngLat(bounds.getLonEast(), y)));
}
features.add(Feature.fromGeometry(MultiLineString.fromLngLats(gridLines)));
gridLines = new ArrayList();
for (double x = Math.floor(bounds.getLonWest() / gridSpacing) * gridSpacing;
x <= Math.ceil(bounds.getLonEast() / gridSpacing) * gridSpacing; x += gridSpacing) {
gridLines.add(Arrays.asList(Point.fromLngLat(x, bounds.getLatSouth()),
Point.fromLngLat(x, bounds.getLatNorth())));
}
features.add(Feature.fromGeometry(MultiLineString.fromLngLats(gridLines)));
return FeatureCollection.fromFeatures(features);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_grid_source);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
}
@Override
public void onMapReady(@NonNull final MapboxMap map) {
source = new CustomGeometrySource(ID_GRID_SOURCE, new GridProvider());
layer = new LineLayer(ID_GRID_LAYER, ID_GRID_SOURCE);
layer.setProperties(
lineColor(Color.parseColor("#000000"))
);
map.setStyle(new Style.Builder()
.fromUri(Style.MAPBOX_STREETS)
.withLayer(layer)
.withSource(source)
);
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
public void onResume() {
super.onResume();
mapView.onResume();
}
@Override
public void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
}

View File

@@ -0,0 +1,228 @@
package com.mapbox.mapboxsdk.testapp.activity.style;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.style.layers.CircleLayer;
import com.mapbox.mapboxsdk.style.layers.HeatmapLayer;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import com.mapbox.mapboxsdk.testapp.R;
import timber.log.Timber;
import java.net.URI;
import java.net.URISyntaxException;
import static com.mapbox.mapboxsdk.style.expressions.Expression.get;
import static com.mapbox.mapboxsdk.style.expressions.Expression.heatmapDensity;
import static com.mapbox.mapboxsdk.style.expressions.Expression.interpolate;
import static com.mapbox.mapboxsdk.style.expressions.Expression.linear;
import static com.mapbox.mapboxsdk.style.expressions.Expression.literal;
import static com.mapbox.mapboxsdk.style.expressions.Expression.rgb;
import static com.mapbox.mapboxsdk.style.expressions.Expression.rgba;
import static com.mapbox.mapboxsdk.style.expressions.Expression.stop;
import static com.mapbox.mapboxsdk.style.expressions.Expression.zoom;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleOpacity;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleRadius;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleStrokeColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleStrokeWidth;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.heatmapColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.heatmapIntensity;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.heatmapOpacity;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.heatmapRadius;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.heatmapWeight;
/**
* Test activity showcasing the heatmap layer api.
*/
public class HeatmapLayerActivity extends AppCompatActivity {
private static final String EARTHQUAKE_SOURCE_URL = "https://www.mapbox.com/mapbox-gl-js/assets/earthquakes.geojson";
private static final String EARTHQUAKE_SOURCE_ID = "earthquakes";
private static final String HEATMAP_LAYER_ID = "earthquakes-heat";
private static final String HEATMAP_LAYER_SOURCE = "earthquakes";
private static final String CIRCLE_LAYER_ID = "earthquakes-circle";
private MapView mapView;
private MapboxMap mapboxMap;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_heatmaplayer);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(map -> {
mapboxMap = map;
try {
mapboxMap.setStyle(new Style.Builder()
.fromUri(Style.DARK)
.withSource(createEarthquakeSource())
.withLayerAbove(createHeatmapLayer(), "waterway-label")
.withLayerBelow(createCircleLayer(), HEATMAP_LAYER_ID)
);
} catch (URISyntaxException exception) {
Timber.e(exception);
}
});
}
private GeoJsonSource createEarthquakeSource() throws URISyntaxException {
return new GeoJsonSource(EARTHQUAKE_SOURCE_ID, new URI(EARTHQUAKE_SOURCE_URL));
}
private HeatmapLayer createHeatmapLayer() {
HeatmapLayer layer = new HeatmapLayer(HEATMAP_LAYER_ID, EARTHQUAKE_SOURCE_ID);
layer.setMaxZoom(9);
layer.setSourceLayer(HEATMAP_LAYER_SOURCE);
layer.setProperties(
// Color ramp for heatmap. Domain is 0 (low) to 1 (high).
// Begin color ramp at 0-stop with a 0-transparancy color
// to create a blur-like effect.
heatmapColor(
interpolate(
linear(), heatmapDensity(),
literal(0), rgba(33, 102, 172, 0),
literal(0.2), rgb(103, 169, 207),
literal(0.4), rgb(209, 229, 240),
literal(0.6), rgb(253, 219, 199),
literal(0.8), rgb(239, 138, 98),
literal(1), rgb(178, 24, 43)
)
),
// Increase the heatmap weight based on frequency and property magnitude
heatmapWeight(
interpolate(
linear(), get("mag"),
stop(0, 0),
stop(6, 1)
)
),
// Increase the heatmap color weight weight by zoom level
// heatmap-intensity is a multiplier on top of heatmap-weight
heatmapIntensity(
interpolate(
linear(), zoom(),
stop(0, 1),
stop(9, 3)
)
),
// Adjust the heatmap radius by zoom level
heatmapRadius(
interpolate(
linear(), zoom(),
stop(0, 2),
stop(9, 20)
)
),
// Transition from heatmap to circle layer by zoom level
heatmapOpacity(
interpolate(
linear(), zoom(),
stop(7, 1),
stop(9, 0)
)
)
);
return layer;
}
private CircleLayer createCircleLayer() {
CircleLayer circleLayer = new CircleLayer(CIRCLE_LAYER_ID, EARTHQUAKE_SOURCE_ID);
circleLayer.setProperties(
// Size circle radius by earthquake magnitude and zoom level
circleRadius(
interpolate(
linear(), zoom(),
literal(7), interpolate(
linear(), get("mag"),
stop(1, 1),
stop(6, 4)
),
literal(16), interpolate(
linear(), get("mag"),
stop(1, 5),
stop(6, 50)
)
)
),
// Color circle by earthquake magnitude
circleColor(
interpolate(
linear(), get("mag"),
literal(1), rgba(33, 102, 172, 0),
literal(2), rgb(103, 169, 207),
literal(3), rgb(209, 229, 240),
literal(4), rgb(253, 219, 199),
literal(5), rgb(239, 138, 98),
literal(6), rgb(178, 24, 43)
)
),
// Transition from heatmap to circle layer by zoom level
circleOpacity(
interpolate(
linear(), zoom(),
stop(7, 0),
stop(8, 1)
)
),
circleStrokeColor("white"),
circleStrokeWidth(1.0f)
);
return circleLayer;
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
public void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
}

View File

@@ -0,0 +1,87 @@
package com.mapbox.mapboxsdk.testapp.activity.style;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.style.layers.HillshadeLayer;
import com.mapbox.mapboxsdk.style.sources.RasterDemSource;
import com.mapbox.mapboxsdk.testapp.R;
/**
* Test activity showcasing using HillshadeLayer.
*/
public class HillshadeLayerActivity extends AppCompatActivity {
private static final String LAYER_ID = "hillshade-layer";
private static final String LAYER_BELOW_ID = "waterway-river-canal";
private static final String SOURCE_ID = "hillshade-source";
private static final String SOURCE_URL = "mapbox://mapbox.terrain-rgb";
private MapView mapView;
private MapboxMap mapboxMap;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fill_extrusion_layer);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(map -> {
mapboxMap = map;
RasterDemSource rasterDemSource = new RasterDemSource(SOURCE_ID, SOURCE_URL);
HillshadeLayer hillshadeLayer = new HillshadeLayer(LAYER_ID, SOURCE_ID);
mapboxMap.setStyle(new Style.Builder()
.fromUri(Style.MAPBOX_STREETS)
.withLayerBelow(hillshadeLayer, LAYER_BELOW_ID)
.withSource(rasterDemSource)
);
});
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
public void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
}

View File

@@ -0,0 +1,84 @@
package com.mapbox.mapboxsdk.testapp.activity.style
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.support.v4.content.res.ResourcesCompat
import android.support.v7.app.AppCompatActivity
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory
import com.mapbox.mapboxsdk.geometry.LatLng
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 com.mapbox.mapboxsdk.testapp.R
import java.net.URI
import kotlinx.android.synthetic.main.activity_map_simple.*
/**
* Activity showcasing how to load symbols on a map without a Style URI or Style JSON.
*/
class NoStyleActivity : AppCompatActivity() {
private val imageIcon: Drawable by lazy {
ResourcesCompat.getDrawable(resources, R.drawable.ic_add_white, theme)!!
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_map_simple)
mapView.getMapAsync { map ->
map.moveCamera(CameraUpdateFactory.newLatLngZoom(cameraTarget, cameraZoom))
map.setStyle(
Style.Builder()
.withImage(imageId, imageIcon)
.withSource(GeoJsonSource(sourceId, URI("asset://points-sf.geojson")))
.withLayer(SymbolLayer(layerId, sourceId).withProperties(iconImage(imageId)))
)
}
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
override fun onDestroy() {
super.onDestroy()
mapView.onDestroy()
}
override fun onSaveInstanceState(outState: Bundle?) {
super.onSaveInstanceState(outState)
outState?.let {
mapView.onSaveInstanceState(it)
}
}
companion object {
const val layerId = "custom-layer-id"
const val sourceId = "custom-source-id"
const val imageId = "image-id"
const val cameraZoom = 10.0
val cameraTarget = LatLng(37.758912, -122.442578)
}
}

View File

@@ -0,0 +1,129 @@
package com.mapbox.mapboxsdk.testapp.activity.style;
import android.os.Bundle;
import android.os.Handler;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
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.mapboxsdk.testapp.R;
import timber.log.Timber;
import java.net.URI;
import java.net.URISyntaxException;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage;
/**
* Test activity showcasing using realtime GeoJSON to move a symbol on your map
* <p>
* GL-native equivalent of https://www.mapbox.com/mapbox-gl-js/example/live-geojson/
* </p>
*/
public class RealTimeGeoJsonActivity extends AppCompatActivity implements OnMapReadyCallback {
private static final String ID_GEOJSON_LAYER = "wanderdrone";
private static final String ID_GEOJSON_SOURCE = ID_GEOJSON_LAYER;
private static final String URL_GEOJSON_SOURCE = "https://wanderdrone.appspot.com/";
private MapView mapView;
private MapboxMap mapboxMap;
private Handler handler;
private Runnable runnable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_default);
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
}
@Override
public void onMapReady(@NonNull final MapboxMap map) {
mapboxMap = map;
mapboxMap.setStyle(Style.MAPBOX_STREETS, new Style.OnStyleLoaded() {
@Override
public void onStyleLoaded(@NonNull Style style) {
// add source
try {
style.addSource(new GeoJsonSource(ID_GEOJSON_SOURCE, new URI(URL_GEOJSON_SOURCE)));
} catch (URISyntaxException malformedUriException) {
Timber.e(malformedUriException, "Invalid URL");
}
// add layer
SymbolLayer layer = new SymbolLayer(ID_GEOJSON_LAYER, ID_GEOJSON_SOURCE);
layer.setProperties(iconImage("rocket-15"));
style.addLayer(layer);
// loop refresh geojson
handler = new Handler();
runnable = new RefreshGeoJsonRunnable(mapboxMap, handler);
handler.postDelayed(runnable, 2000);
}
});
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
public void onResume() {
super.onResume();
mapView.onResume();
}
@Override
public void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
handler.removeCallbacks(runnable);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
private static class RefreshGeoJsonRunnable implements Runnable {
private MapboxMap mapboxMap;
private Handler handler;
RefreshGeoJsonRunnable(MapboxMap mapboxMap, Handler handler) {
this.mapboxMap = mapboxMap;
this.handler = handler;
}
@Override
public void run() {
((GeoJsonSource) mapboxMap.getStyle().getSource(ID_GEOJSON_SOURCE)).setUrl(URL_GEOJSON_SOURCE);
handler.postDelayed(this, 2000);
}
}
}

View File

@@ -0,0 +1,607 @@
package com.mapbox.mapboxsdk.testapp.activity.style;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
import com.mapbox.geojson.Feature;
import com.mapbox.geojson.FeatureCollection;
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.Style;
import com.mapbox.mapboxsdk.style.layers.CircleLayer;
import com.mapbox.mapboxsdk.style.layers.FillLayer;
import com.mapbox.mapboxsdk.style.layers.Layer;
import com.mapbox.mapboxsdk.style.layers.LineLayer;
import com.mapbox.mapboxsdk.style.layers.Property;
import com.mapbox.mapboxsdk.style.layers.PropertyValue;
import com.mapbox.mapboxsdk.style.layers.RasterLayer;
import com.mapbox.mapboxsdk.style.layers.SymbolLayer;
import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import com.mapbox.mapboxsdk.style.sources.RasterSource;
import com.mapbox.mapboxsdk.style.sources.Source;
import com.mapbox.mapboxsdk.style.sources.TileSet;
import com.mapbox.mapboxsdk.style.sources.VectorSource;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.utils.ResourceUtils;
import timber.log.Timber;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static com.mapbox.mapboxsdk.style.expressions.Expression.all;
import static com.mapbox.mapboxsdk.style.expressions.Expression.color;
import static com.mapbox.mapboxsdk.style.expressions.Expression.eq;
import static com.mapbox.mapboxsdk.style.expressions.Expression.exponential;
import static com.mapbox.mapboxsdk.style.expressions.Expression.get;
import static com.mapbox.mapboxsdk.style.expressions.Expression.gte;
import static com.mapbox.mapboxsdk.style.expressions.Expression.interpolate;
import static com.mapbox.mapboxsdk.style.expressions.Expression.literal;
import static com.mapbox.mapboxsdk.style.expressions.Expression.lt;
import static com.mapbox.mapboxsdk.style.expressions.Expression.stop;
import static com.mapbox.mapboxsdk.style.expressions.Expression.toNumber;
import static com.mapbox.mapboxsdk.style.expressions.Expression.zoom;
import static com.mapbox.mapboxsdk.style.layers.Property.FILL_TRANSLATE_ANCHOR_MAP;
import static com.mapbox.mapboxsdk.style.layers.Property.NONE;
import static com.mapbox.mapboxsdk.style.layers.Property.SYMBOL_PLACEMENT_POINT;
import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.backgroundOpacity;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillAntialias;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillOpacity;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillOutlineColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillTranslateAnchor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineCap;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineJoin;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineOpacity;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineWidth;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.symbolPlacement;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility;
/**
* Test activity showcasing the runtime style API.
*/
public class RuntimeStyleActivity extends AppCompatActivity {
private MapView mapView;
private MapboxMap mapboxMap;
private boolean styleLoaded;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_runtime_style);
// Initialize map as normal
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(map -> {
// Store for later
mapboxMap = map;
// Center and Zoom (Amsterdam, zoomed to streets)
mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(52.379189, 4.899431), 14));
mapboxMap.setStyle(
new Style.Builder()
.fromUri(Style.MAPBOX_STREETS)
// set custom transition
.withTransition(new TransitionOptions(250, 50)), style -> styleLoaded = true
);
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_runtime_style, menu);
return true;
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (!styleLoaded) {
return false;
}
switch (item.getItemId()) {
case R.id.action_list_layers:
listLayers();
return true;
case R.id.action_list_sources:
listSources();
return true;
case R.id.action_water_color:
setWaterColor();
return true;
case R.id.action_background_opacity:
setBackgroundOpacity();
return true;
case R.id.action_road_avoid_edges:
setRoadSymbolPlacement();
return true;
case R.id.action_layer_visibility:
setLayerInvisible();
return true;
case R.id.action_remove_layer:
removeBuildings();
return true;
case R.id.action_add_parks_layer:
addParksLayer();
return true;
case R.id.action_add_dynamic_parks_layer:
addDynamicParksLayer();
return true;
case R.id.action_add_terrain_layer:
addTerrainLayer();
return true;
case R.id.action_add_satellite_layer:
addSatelliteLayer();
return true;
case R.id.action_update_water_color_on_zoom:
updateWaterColorOnZoom();
return true;
case R.id.action_add_custom_tiles:
addCustomTileSource();
return true;
case R.id.action_fill_filter:
styleFillFilterLayer();
return true;
case R.id.action_line_filter:
styleLineFilterLayer();
return true;
case R.id.action_numeric_filter:
styleNumericFillLayer();
return true;
case R.id.action_bring_water_to_front:
bringWaterToFront();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void listLayers() {
List<Layer> layers = mapboxMap.getStyle().getLayers();
StringBuilder builder = new StringBuilder("Layers:");
for (Layer layer : layers) {
builder.append("\n");
builder.append(layer.getId());
}
Toast.makeText(this, builder.toString(), Toast.LENGTH_LONG).show();
}
private void listSources() {
List<Source> sources = mapboxMap.getStyle().getSources();
StringBuilder builder = new StringBuilder("Sources:");
for (Source source : sources) {
builder.append("\n");
builder.append(source.getId());
}
Toast.makeText(this, builder.toString(), Toast.LENGTH_LONG).show();
}
private void setLayerInvisible() {
String[] roadLayers = new String[] {"water"};
for (String roadLayer : roadLayers) {
Layer layer = mapboxMap.getStyle().getLayer(roadLayer);
if (layer != null) {
layer.setProperties(visibility(NONE));
}
}
}
private void setRoadSymbolPlacement() {
// Zoom so that the labels are visible first
mapboxMap.animateCamera(CameraUpdateFactory.zoomTo(14), new DefaultCallback() {
@Override
public void onFinish() {
String[] roadLayers = new String[] {"road-label-small", "road-label-medium", "road-label-large"};
for (String roadLayer : roadLayers) {
Layer layer = mapboxMap.getStyle().getLayer(roadLayer);
if (layer != null) {
layer.setProperties(symbolPlacement(SYMBOL_PLACEMENT_POINT));
}
}
}
});
}
private void setBackgroundOpacity() {
Layer background = mapboxMap.getStyle().getLayer("background");
if (background != null) {
background.setProperties(backgroundOpacity(0.2f));
}
}
private void setWaterColor() {
FillLayer water = mapboxMap.getStyle().getLayerAs("water");
if (water != null) {
water.setFillColorTransition(new TransitionOptions(7500, 1000));
water.setProperties(
visibility(VISIBLE),
fillColor(Color.RED)
);
} else {
Toast.makeText(RuntimeStyleActivity.this, "No water layer in this style", Toast.LENGTH_SHORT).show();
}
}
private void removeBuildings() {
// Zoom to see buildings first
mapboxMap.getStyle().removeLayer("building");
}
private void addParksLayer() {
// Add a source
Source source;
try {
source = new GeoJsonSource("amsterdam-spots", ResourceUtils.readRawResource(this, R.raw.amsterdam));
} catch (IOException ioException) {
Toast.makeText(
RuntimeStyleActivity.this,
"Couldn't add source: " + ioException.getMessage(),
Toast.LENGTH_SHORT).show();
return;
}
mapboxMap.getStyle().addSource(source);
FillLayer layer = new FillLayer("parksLayer", "amsterdam-spots");
layer.setProperties(
fillColor(Color.RED),
fillOutlineColor(Color.BLUE),
fillOpacity(0.3f),
fillAntialias(true)
);
// Only show me parks (except westerpark with stroke-width == 3)
layer.setFilter(all(eq(get("type"), literal("park")), eq(get("stroke-width"), literal(3))));
mapboxMap.getStyle().addLayerBelow(layer, "building");
// layer.setPaintProperty(fillColor(Color.RED)); // XXX But not after the object is attached
// Or get the object later and set it. It's all good.
mapboxMap.getStyle().getLayer("parksLayer").setProperties(fillColor(Color.RED));
// You can get a typed layer, if you're sure it's of that type. Use with care
layer = mapboxMap.getStyle().getLayerAs("parksLayer");
// And get some properties
PropertyValue<Boolean> fillAntialias = layer.getFillAntialias();
Timber.d("Fill anti alias: %s", fillAntialias.getValue());
layer.setProperties(fillTranslateAnchor(FILL_TRANSLATE_ANCHOR_MAP));
PropertyValue<String> fillTranslateAnchor = layer.getFillTranslateAnchor();
Timber.d("Fill translate anchor: %s", fillTranslateAnchor.getValue());
PropertyValue<String> visibility = layer.getVisibility();
Timber.d("Visibility: %s", visibility.getValue());
// Get a good look at it all
mapboxMap.animateCamera(CameraUpdateFactory.zoomTo(12));
}
private void addDynamicParksLayer() {
// Load some data
FeatureCollection parks;
try {
String json = ResourceUtils.readRawResource(this, R.raw.amsterdam);
parks = FeatureCollection.fromJson(json);
} catch (IOException ioException) {
Toast.makeText(
RuntimeStyleActivity.this,
"Couldn't add source: " + ioException.getMessage(),
Toast.LENGTH_SHORT
).show();
return;
}
// Add an empty source
mapboxMap.getStyle().addSource(new GeoJsonSource("dynamic-park-source"));
FillLayer layer = new FillLayer("dynamic-parks-layer", "dynamic-park-source");
layer.setProperties(
fillColor(Color.GREEN),
fillOutlineColor(Color.GREEN),
fillOpacity(0.8f),
fillAntialias(true)
);
// Only show me parks
layer.setFilter(all(eq(get("type"), literal("park"))));
mapboxMap.getStyle().addLayer(layer);
// Get a good look at it all
mapboxMap.animateCamera(CameraUpdateFactory.zoomTo(12));
// Animate the parks source
animateParksSource(parks, 0);
}
private void animateParksSource(final FeatureCollection parks, final int counter) {
Handler handler = new Handler(getMainLooper());
handler.postDelayed(() -> {
if (mapboxMap == null) {
return;
}
Timber.d("Updating parks source");
// change the source
int park = counter < parks.features().size() - 1 ? counter : 0;
GeoJsonSource source = mapboxMap.getStyle().getSourceAs("dynamic-park-source");
if (source == null) {
Timber.e("Source not found");
Toast.makeText(RuntimeStyleActivity.this, "Source not found", Toast.LENGTH_SHORT).show();
return;
}
List<Feature> features = new ArrayList<>();
features.add(parks.features().get(park));
source.setGeoJson(FeatureCollection.fromFeatures(features));
// Re-post
animateParksSource(parks, park + 1);
}, counter == 0 ? 100 : 1000);
}
private void addTerrainLayer() {
// Add a source
Source source = new VectorSource("my-terrain-source", "mapbox://mapbox.mapbox-terrain-v2");
mapboxMap.getStyle().addSource(source);
LineLayer layer = new LineLayer("terrainLayer", "my-terrain-source");
layer.setSourceLayer("contour");
layer.setProperties(
lineJoin(Property.LINE_JOIN_ROUND),
lineCap(Property.LINE_CAP_ROUND),
lineColor(Color.RED),
lineWidth(20f)
);
// adding layers below "road" layers
List<Layer> layers = mapboxMap.getStyle().getLayers();
Layer latestLayer = null;
Collections.reverse(layers);
for (Layer currentLayer : layers) {
if (currentLayer instanceof FillLayer && ((FillLayer) currentLayer).getSourceLayer().equals("road")) {
latestLayer = currentLayer;
} else if (currentLayer instanceof CircleLayer && ((CircleLayer) currentLayer).getSourceLayer().equals("road")) {
latestLayer = currentLayer;
} else if (currentLayer instanceof SymbolLayer && ((SymbolLayer) currentLayer).getSourceLayer().equals("road")) {
latestLayer = currentLayer;
} else if (currentLayer instanceof LineLayer && ((LineLayer) currentLayer).getSourceLayer().equals("road")) {
latestLayer = currentLayer;
}
}
if (latestLayer != null) {
mapboxMap.getStyle().addLayerBelow(layer, latestLayer.getId());
}
// Need to get a fresh handle
layer = mapboxMap.getStyle().getLayerAs("terrainLayer");
// Make sure it's also applied after the fact
layer.setMinZoom(10);
layer.setMaxZoom(15);
layer = (LineLayer) mapboxMap.getStyle().getLayer("terrainLayer");
Toast.makeText(this, String.format(
"Set min/max zoom to %s - %s", layer.getMinZoom(), layer.getMaxZoom()), Toast.LENGTH_SHORT).show();
}
private void addSatelliteLayer() {
// Add a source
Source source = new RasterSource("my-raster-source", "mapbox://mapbox.satellite", 512);
mapboxMap.getStyle().addSource(source);
// Add a layer
mapboxMap.getStyle().addLayer(new RasterLayer("satellite-layer", "my-raster-source"));
}
private void updateWaterColorOnZoom() {
FillLayer layer = mapboxMap.getStyle().getLayerAs("water");
if (layer == null) {
return;
}
// Set a zoom function to update the color of the water
layer.setProperties(
fillColor(
interpolate(
exponential(0.8f),
zoom(),
stop(1, color(Color.GREEN)),
stop(4, color(Color.BLUE)),
stop(12, color(Color.RED)),
stop(20, color(Color.BLACK))
)
)
);
// do some animations to show it off properly
mapboxMap.animateCamera(CameraUpdateFactory.zoomTo(1), 1500);
}
private void addCustomTileSource() {
// Add a source
TileSet tileSet = new TileSet("2.1.0", "https://d25uarhxywzl1j.cloudfront.net/v0.1/{z}/{x}/{y}.mvt");
tileSet.setMinZoom(0);
tileSet.setMaxZoom(14);
Source source = new VectorSource("custom-tile-source", tileSet);
mapboxMap.getStyle().addSource(source);
// Add a layer
LineLayer lineLayer = new LineLayer("custom-tile-layers", "custom-tile-source");
lineLayer.setSourceLayer("mapillary-sequences");
lineLayer.setProperties(
lineCap(Property.LINE_CAP_ROUND),
lineJoin(Property.LINE_JOIN_ROUND),
lineOpacity(0.6f),
lineWidth(2.0f),
lineColor(Color.GREEN)
);
mapboxMap.getStyle().addLayer(lineLayer);
}
private void styleFillFilterLayer() {
mapboxMap.setStyle(new Style.Builder().fromUri("asset://fill_filter_style.json"));
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(31, -100), 3));
Handler handler = new Handler(getMainLooper());
handler.postDelayed(() -> {
if (mapboxMap == null) {
return;
}
Timber.d("Styling filtered fill layer");
FillLayer states = (FillLayer) mapboxMap.getStyle().getLayer("states");
if (states != null) {
states.setFilter(eq(get("name"), literal("Texas")));
states.setFillOpacityTransition(new TransitionOptions(2500, 0));
states.setFillColorTransition(new TransitionOptions(2500, 0));
states.setProperties(
fillColor(Color.RED),
fillOpacity(0.25f)
);
} else {
Toast.makeText(RuntimeStyleActivity.this, "No states layer in this style", Toast.LENGTH_SHORT).show();
}
}, 2000);
}
private void styleLineFilterLayer() {
mapboxMap.setStyle(new Style.Builder().fromUri("asset://line_filter_style.json"));
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(40, -97), 5));
Handler handler = new Handler(getMainLooper());
handler.postDelayed(() -> {
if (mapboxMap == null) {
return;
}
Timber.d("Styling filtered line layer");
LineLayer counties = (LineLayer) mapboxMap.getStyle().getLayer("counties");
if (counties != null) {
counties.setFilter(eq(get("NAME10"), "Washington"));
counties.setProperties(
lineColor(Color.RED),
lineOpacity(0.75f),
lineWidth(5f)
);
} else {
Toast.makeText(RuntimeStyleActivity.this, "No counties layer in this style", Toast.LENGTH_SHORT).show();
}
}, 2000);
}
private void styleNumericFillLayer() {
mapboxMap.setStyle(new Style.Builder().fromUri("asset://numeric_filter_style.json"));
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(40, -97), 5));
Handler handler = new Handler(getMainLooper());
handler.postDelayed(() -> {
if (mapboxMap == null) {
return;
}
Timber.d("Styling numeric fill layer");
FillLayer regions = (FillLayer) mapboxMap.getStyle().getLayer("regions");
if (regions != null) {
regions.setFilter(all(
gte(toNumber(get("HRRNUM")), literal(200)),
lt(toNumber(get("HRRNUM")), literal(300)))
);
regions.setProperties(
fillColor(Color.BLUE),
fillOpacity(0.5f)
);
} else {
Toast.makeText(RuntimeStyleActivity.this, "No regions layer in this style", Toast.LENGTH_SHORT).show();
}
}, 2000);
}
private void bringWaterToFront() {
Layer water = mapboxMap.getStyle().getLayer("water");
if (water != null) {
mapboxMap.getStyle().removeLayer(water);
mapboxMap.getStyle().addLayerAt(water, mapboxMap.getStyle().getLayers().size() - 1);
} else {
Toast.makeText(this, "No water layer in this style", Toast.LENGTH_SHORT).show();
}
}
private static class DefaultCallback implements MapboxMap.CancelableCallback {
@Override
public void onCancel() {
// noop
}
@Override
public void onFinish() {
// noop
}
}
}

View File

@@ -0,0 +1,99 @@
package com.mapbox.mapboxsdk.testapp.activity.style;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.style.layers.CircleLayer;
import com.mapbox.mapboxsdk.style.sources.VectorSource;
import com.mapbox.mapboxsdk.testapp.R;
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.visibility;
/**
* Test activity for unit test execution
*/
public class RuntimeStyleTimingTestActivity extends AppCompatActivity {
public MapView mapView;
private MapboxMap mapboxMap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_runtime_style);
// Initialize map as normal
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(mapboxMap -> {
RuntimeStyleTimingTestActivity.this.mapboxMap = mapboxMap;
CircleLayer museumsLayer = new CircleLayer("museums", "museums_source");
museumsLayer.setSourceLayer("museum-cusco");
museumsLayer.setProperties(
visibility(VISIBLE),
circleRadius(8f),
circleColor(Color.argb(1, 55, 148, 179))
);
VectorSource museums = new VectorSource("museums_source", "mapbox://mapbox.2opop9hr");
mapboxMap.setStyle(new Style.Builder()
.fromUri(Style.MAPBOX_STREETS)
.withSource(museums)
.withLayer(museumsLayer));
});
}
public MapboxMap getMapboxMap() {
return mapboxMap;
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}

View File

@@ -0,0 +1,177 @@
package com.mapbox.mapboxsdk.testapp.activity.style;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.utils.ResourceUtils;
import timber.log.Timber;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.ref.WeakReference;
/**
* Test activity showcasing how to use a file:// resource for the style.json and how to use MapboxMap#setStyleJson.
*/
public class StyleFileActivity extends AppCompatActivity {
private MapboxMap mapboxMap;
private MapView mapView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_style_file);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(map -> {
mapboxMap = map;
mapboxMap.setStyle(Style.MAPBOX_STREETS, style -> {
FloatingActionButton fab = findViewById(R.id.fab_file);
fab.setColorFilter(ContextCompat.getColor(StyleFileActivity.this, R.color.primary));
fab.setOnClickListener(view -> new CreateStyleFileTask(view.getContext(), mapboxMap).execute());
FloatingActionButton fabStyleJson = findViewById(R.id.fab_style_json);
fabStyleJson.setColorFilter(ContextCompat.getColor(StyleFileActivity.this, R.color.primary));
fabStyleJson.setOnClickListener(view -> new LoadStyleFileTask(view.getContext(), mapboxMap).execute());
});
});
}
/**
* Task to read a style file from the raw folder
*/
private static class LoadStyleFileTask extends AsyncTask<Void, Void, String> {
private WeakReference<Context> context;
private WeakReference<MapboxMap> mapboxMap;
LoadStyleFileTask(Context context, MapboxMap mapboxMap) {
this.context = new WeakReference<>(context);
this.mapboxMap = new WeakReference<>(mapboxMap);
}
@Override
protected String doInBackground(Void... voids) {
String styleJson = "";
try {
styleJson = ResourceUtils.readRawResource(context.get(), R.raw.sat_style);
} catch (Exception exception) {
Timber.e(exception, "Can't load local file style");
}
return styleJson;
}
@Override
protected void onPostExecute(String json) {
super.onPostExecute(json);
Timber.d("Read json, %s", json);
MapboxMap mapboxMap = this.mapboxMap.get();
if (mapboxMap != null) {
mapboxMap.setStyle(new Style.Builder().fromJson(json));
}
}
}
/**
* Task to write a style file to local disk and load it in the map view
*/
private static class CreateStyleFileTask extends AsyncTask<Void, Integer, Long> {
private File cacheStyleFile;
private WeakReference<Context> context;
private WeakReference<MapboxMap> mapboxMap;
CreateStyleFileTask(Context context, MapboxMap mapboxMap) {
this.context = new WeakReference<>(context);
this.mapboxMap = new WeakReference<>(mapboxMap);
}
@Override
protected Long doInBackground(Void... params) {
try {
cacheStyleFile = File.createTempFile("my-", ".style.json");
cacheStyleFile.createNewFile();
Timber.i("Writing style file to: %s", cacheStyleFile.getAbsolutePath());
Context context = this.context.get();
if (context != null) {
writeToFile(cacheStyleFile, ResourceUtils.readRawResource(context, R.raw.local_style));
}
} catch (Exception exception) {
Toast.makeText(context.get(), "Could not create style file in cache dir", Toast.LENGTH_SHORT).show();
}
return 1L;
}
protected void onPostExecute(Long result) {
// Actual file:// usage
MapboxMap mapboxMap = this.mapboxMap.get();
if (mapboxMap != null) {
mapboxMap.setStyle(new Style.Builder().fromUri("file://" + cacheStyleFile.getAbsolutePath()));
}
}
private void writeToFile(File file, String contents) throws IOException {
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new FileWriter(file));
writer.write(contents);
} finally {
if (writer != null) {
writer.close();
}
}
}
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
public void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
}

View File

@@ -0,0 +1,368 @@
package com.mapbox.mapboxsdk.testapp.activity.style;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PointF;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.mapbox.geojson.Feature;
import com.mapbox.geojson.FeatureCollection;
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.expressions.Expression;
import com.mapbox.mapboxsdk.style.layers.SymbolLayer;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import com.mapbox.mapboxsdk.style.sources.Source;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.utils.ResourceUtils;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.List;
import timber.log.Timber;
import static com.mapbox.mapboxsdk.style.expressions.Expression.concat;
import static com.mapbox.mapboxsdk.style.expressions.Expression.division;
import static com.mapbox.mapboxsdk.style.expressions.Expression.downcase;
import static com.mapbox.mapboxsdk.style.expressions.Expression.eq;
import static com.mapbox.mapboxsdk.style.expressions.Expression.get;
import static com.mapbox.mapboxsdk.style.expressions.Expression.literal;
import static com.mapbox.mapboxsdk.style.expressions.Expression.match;
import static com.mapbox.mapboxsdk.style.expressions.Expression.number;
import static com.mapbox.mapboxsdk.style.expressions.Expression.pi;
import static com.mapbox.mapboxsdk.style.expressions.Expression.product;
import static com.mapbox.mapboxsdk.style.expressions.Expression.rgba;
import static com.mapbox.mapboxsdk.style.expressions.Expression.step;
import static com.mapbox.mapboxsdk.style.expressions.Expression.stop;
import static com.mapbox.mapboxsdk.style.expressions.Expression.string;
import static com.mapbox.mapboxsdk.style.expressions.Expression.upcase;
import static com.mapbox.mapboxsdk.style.expressions.Expression.zoom;
import static com.mapbox.mapboxsdk.style.layers.Property.ICON_ANCHOR_BOTTOM;
import static com.mapbox.mapboxsdk.style.layers.Property.TEXT_ANCHOR_TOP;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAllowOverlap;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAnchor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconOffset;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconOpacity;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconSize;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textAnchor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textField;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textSize;
/**
* Test activity showcasing using a symbol generator that generates Bitmaps from Android SDK Views.
*/
public class SymbolGeneratorActivity extends AppCompatActivity implements OnMapReadyCallback {
private static final String SOURCE_ID = "com.mapbox.mapboxsdk.style.layers.symbol.source.id";
private static final String LAYER_ID = "com.mapbox.mapboxsdk.style.layers.symbol.layer.id";
private static final String FEATURE_ID = "brk_name";
private static final String FEATURE_RANK = "scalerank";
private static final String FEATURE_NAME = "name_sort";
private static final String FEATURE_TYPE = "type";
private static final String FEATURE_REGION = "continent";
private MapView mapView;
private MapboxMap mapboxMap;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_symbol_generator);
mapView = (MapView) findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this);
}
@Override
public void onMapReady(@NonNull final MapboxMap map) {
mapboxMap = map;
map.setStyle(Style.OUTDOORS, style -> {
addSymbolClickListener();
new LoadDataTask(SymbolGeneratorActivity.this).execute();
});
}
private void addSymbolClickListener() {
mapboxMap.addOnMapClickListener(point -> {
PointF screenPoint = mapboxMap.getProjection().toScreenLocation(point);
List<Feature> features = mapboxMap.queryRenderedFeatures(screenPoint, LAYER_ID);
if (!features.isEmpty()) {
Feature feature = features.get(0);
// validate symbol flicker regression for #13407
SymbolLayer layer = mapboxMap.getStyle().getLayerAs(LAYER_ID);
layer.setProperties(iconOpacity(match(
get(FEATURE_ID), literal(1.0f),
stop(feature.getStringProperty(FEATURE_ID), 0.3f)
)));
Timber.v("Feature was clicked with data: %s", feature.toJson());
Toast.makeText(
SymbolGeneratorActivity.this,
"hello from: " + feature.getStringProperty(FEATURE_NAME),
Toast.LENGTH_LONG).show();
}
return false;
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_generator_symbol, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == R.id.menu_action_icon_overlap) {
SymbolLayer layer = mapboxMap.getStyle().getLayerAs(LAYER_ID);
layer.setProperties(iconAllowOverlap(!layer.getIconAllowOverlap().getValue()));
return true;
} else if (item.getItemId() == R.id.menu_action_filter) {
SymbolLayer layer = mapboxMap.getStyle().getLayerAs(LAYER_ID);
layer.setFilter(eq(get(FEATURE_RANK), literal(1)));
Timber.e("Filter that was set: %s", layer.getFilter());
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
public void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
/**
* Utility class to generate Bitmaps for Symbol.
* <p>
* Bitmaps can be added to the map with {@link com.mapbox.mapboxsdk.maps.MapboxMap#addImage(String, Bitmap)}
* </p>
*/
private static class SymbolGenerator {
/**
* Generate a Bitmap from an Android SDK View.
*
* @param view the View to be drawn to a Bitmap
* @return the generated bitmap
*/
public static Bitmap generate(@NonNull View view) {
int measureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
view.measure(measureSpec, measureSpec);
int measuredWidth = view.getMeasuredWidth();
int measuredHeight = view.getMeasuredHeight();
view.layout(0, 0, measuredWidth, measuredHeight);
Bitmap bitmap = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888);
bitmap.eraseColor(Color.TRANSPARENT);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
return bitmap;
}
}
private static class LoadDataTask extends AsyncTask<Void, Void, FeatureCollection> {
private WeakReference<SymbolGeneratorActivity> activity;
LoadDataTask(SymbolGeneratorActivity activity) {
this.activity = new WeakReference<>(activity);
}
@Override
protected FeatureCollection doInBackground(Void... params) {
Context context = activity.get();
if (context != null) {
try {
// read local geojson from raw folder
String tinyCountriesJson = ResourceUtils.readRawResource(context, R.raw.tiny_countries);
return FeatureCollection.fromJson(tinyCountriesJson);
} catch (IOException exception) {
Timber.e(exception);
}
}
return null;
}
@Override
protected void onPostExecute(FeatureCollection featureCollection) {
super.onPostExecute(featureCollection);
SymbolGeneratorActivity activity = this.activity.get();
if (featureCollection == null || activity == null) {
return;
}
activity.onDataLoaded(featureCollection);
}
}
public void onDataLoaded(@NonNull FeatureCollection featureCollection) {
if (mapView.isDestroyed()) {
return;
}
// create expressions
Expression iconImageExpression = string(get(literal(FEATURE_ID)));
Expression iconSizeExpression = division(number(get(literal(FEATURE_RANK))), literal(2.0f));
Expression textSizeExpression = product(get(literal(FEATURE_RANK)), pi());
Expression textFieldExpression = concat(upcase(literal("a ")), upcase(string(get(literal(FEATURE_TYPE)))),
downcase(literal(" IN ")), string(get(literal(FEATURE_REGION)))
);
Expression textColorExpression = match(get(literal(FEATURE_RANK)),
literal(1), rgba(255, 0, 0, 1.0f),
literal(2), rgba(0, 0, 255.0f, 1.0f),
rgba(0.0f, 255.0f, 0.0f, 1.0f)
);
rgba(
division(literal(255), get(FEATURE_RANK)),
literal(0.0f),
literal(0.0f),
literal(1.0f)
);
// create symbol layer
SymbolLayer symbolLayer = new SymbolLayer(LAYER_ID, SOURCE_ID)
.withProperties(
// icon configuration
iconImage(iconImageExpression),
iconAllowOverlap(false),
iconSize(iconSizeExpression),
iconAnchor(ICON_ANCHOR_BOTTOM),
iconOffset(step(zoom(), literal(new float[] {0f, 0f}),
stop(1, new Float[] {0f, 0f}),
stop(10, new Float[] {0f, -35f})
)),
// text field configuration
textField(textFieldExpression),
textSize(textSizeExpression),
textAnchor(TEXT_ANCHOR_TOP),
textColor(textColorExpression)
);
// add a geojson source to the map
Source source = new GeoJsonSource(SOURCE_ID, featureCollection);
mapboxMap.getStyle().addSource(source);
// add symbol layer
mapboxMap.getStyle().addLayer(symbolLayer);
// get expressions
Expression iconImageExpressionResult = symbolLayer.getIconImage().getExpression();
Expression iconSizeExpressionResult = symbolLayer.getIconSize().getExpression();
Expression textSizeExpressionResult = symbolLayer.getTextSize().getExpression();
Expression textFieldExpressionResult = symbolLayer.getTextField().getExpression();
Expression textColorExpressionResult = symbolLayer.getTextColor().getExpression();
// log expressions
Timber.e(iconImageExpressionResult.toString());
Timber.e(iconSizeExpressionResult.toString());
Timber.e(textSizeExpressionResult.toString());
Timber.e(textFieldExpressionResult.toString());
Timber.e(textColorExpressionResult.toString());
// reset expressions
symbolLayer.setProperties(
iconImage(iconImageExpressionResult),
iconSize(iconSizeExpressionResult),
textSize(textSizeExpressionResult),
textField(textFieldExpressionResult),
textColor(textColorExpressionResult)
);
new GenerateSymbolTask(mapboxMap, this).execute(featureCollection);
}
private static class GenerateSymbolTask extends AsyncTask<FeatureCollection, Void, HashMap<String, Bitmap>> {
private MapboxMap mapboxMap;
private WeakReference<Context> context;
GenerateSymbolTask(MapboxMap mapboxMap, Context context) {
this.mapboxMap = mapboxMap;
this.context = new WeakReference<>(context);
}
@SuppressWarnings("WrongThread")
@Override
protected HashMap<String, Bitmap> doInBackground(FeatureCollection... params) {
HashMap<String, Bitmap> imagesMap = new HashMap<>();
Context context = this.context.get();
List<Feature> features = params[0].features();
if (context != null && features != null) {
for (Feature feature : features) {
String countryName = feature.getStringProperty(FEATURE_ID);
TextView textView = new TextView(context);
textView.setBackgroundColor(context.getResources().getColor(R.color.blueAccent));
textView.setPadding(10, 5, 10, 5);
textView.setTextColor(Color.WHITE);
textView.setText(countryName);
imagesMap.put(countryName, SymbolGenerator.generate(textView));
}
}
return imagesMap;
}
@Override
protected void onPostExecute(HashMap<String, Bitmap> bitmapHashMap) {
super.onPostExecute(bitmapHashMap);
mapboxMap.getStyle().addImagesAsync(bitmapHashMap);
}
}
}

View File

@@ -0,0 +1,375 @@
package com.mapbox.mapboxsdk.testapp.activity.style;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.PointF;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.ViewGroup;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.mapbox.geojson.Feature;
import com.mapbox.geojson.FeatureCollection;
import com.mapbox.geojson.Point;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.style.expressions.Expression;
import com.mapbox.mapboxsdk.style.layers.Property;
import com.mapbox.mapboxsdk.style.layers.SymbolLayer;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import com.mapbox.mapboxsdk.style.sources.Source;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.utils.BitmapUtils;
import timber.log.Timber;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Random;
import static com.mapbox.mapboxsdk.style.expressions.Expression.FormatOption.formatFontScale;
import static com.mapbox.mapboxsdk.style.expressions.Expression.FormatOption.formatTextColor;
import static com.mapbox.mapboxsdk.style.expressions.Expression.FormatOption.formatTextFont;
import static com.mapbox.mapboxsdk.style.expressions.Expression.NumberFormatOption.currency;
import static com.mapbox.mapboxsdk.style.expressions.Expression.NumberFormatOption.locale;
import static com.mapbox.mapboxsdk.style.expressions.Expression.concat;
import static com.mapbox.mapboxsdk.style.expressions.Expression.format;
import static com.mapbox.mapboxsdk.style.expressions.Expression.formatEntry;
import static com.mapbox.mapboxsdk.style.expressions.Expression.get;
import static com.mapbox.mapboxsdk.style.expressions.Expression.literal;
import static com.mapbox.mapboxsdk.style.expressions.Expression.match;
import static com.mapbox.mapboxsdk.style.expressions.Expression.numberFormat;
import static com.mapbox.mapboxsdk.style.expressions.Expression.rgb;
import static com.mapbox.mapboxsdk.style.expressions.Expression.stop;
import static com.mapbox.mapboxsdk.style.expressions.Expression.switchCase;
import static com.mapbox.mapboxsdk.style.expressions.Expression.toBool;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAllowOverlap;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAnchor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconIgnorePlacement;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconOpacity;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconSize;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textAllowOverlap;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textAnchor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textColor;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textField;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textFont;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textIgnorePlacement;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textRotationAlignment;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textSize;
/**
* Test activity showcasing runtime manipulation of symbol layers.
* <p>
* Showcases the ability to offline render a symbol layer by using a packaged style and fonts from the assets folder.
* </p>
*/
public class SymbolLayerActivity extends AppCompatActivity implements MapboxMap.OnMapClickListener, OnMapReadyCallback {
private static final String ID_FEATURE_PROPERTY = "id";
private static final String SELECTED_FEATURE_PROPERTY = "selected";
private static final String TITLE_FEATURE_PROPERTY = "title";
private static final String[] NORMAL_FONT_STACK = new String[] {"DIN Offc Pro Regular", "Arial Unicode MS Regular"};
private static final String[] BOLD_FONT_STACK = new String[] {"DIN Offc Pro Bold", "Arial Unicode MS Regular"};
// layer & source constants
private static final String MARKER_SOURCE = "marker-source";
private static final String MARKER_LAYER = "marker-layer";
private static final String MAPBOX_SIGN_SOURCE = "mapbox-sign-source";
private static final String MAPBOX_SIGN_LAYER = "mapbox-sign-layer";
private static final String NUMBER_FORMAT_SOURCE = "mapbox-number-source";
private static final String NUMBER_FORMAT_LAYER = "mapbox-number-layer";
private static final Expression TEXT_FIELD_EXPRESSION =
switchCase(toBool(get(SELECTED_FEATURE_PROPERTY)),
format(
formatEntry(
get(TITLE_FEATURE_PROPERTY),
formatTextFont(BOLD_FONT_STACK)
),
formatEntry("\nis fun!", formatFontScale(0.75))
),
format(
formatEntry("This is", formatFontScale(0.75)),
formatEntry(
concat(literal("\n"), get(TITLE_FEATURE_PROPERTY)),
formatFontScale(1.25),
formatTextFont(BOLD_FONT_STACK)
)
)
);
private final Random random = new Random();
private GeoJsonSource markerSource;
private FeatureCollection markerCollection;
private SymbolLayer markerSymbolLayer;
private SymbolLayer mapboxSignSymbolLayer;
private SymbolLayer numberFormatSymbolLayer;
private MapboxMap mapboxMap;
private MapView mapView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_symbollayer);
// Create map configuration
MapboxMapOptions mapboxMapOptions = MapboxMapOptions.createFromAttributes(this);
mapboxMapOptions.camera(new CameraPosition.Builder().target(
new LatLng(52.35273, 4.91638))
.zoom(13)
.build()
);
// Create map programmatically, add to view hierarchy
mapView = new MapView(this, mapboxMapOptions);
mapView.getMapAsync(this);
mapView.onCreate(savedInstanceState);
((ViewGroup) findViewById(R.id.container)).addView(mapView);
// Use OnStyleImageMissing API to lazily load an icon
mapView.addOnStyleImageMissingListener(id -> {
Style style = mapboxMap.getStyle();
if (style != null) {
Timber.e("Adding image with id: %s", id);
Bitmap androidIcon = BitmapUtils.getBitmapFromDrawable(getResources().getDrawable(R.drawable.ic_android_2));
style.addImage(id, Objects.requireNonNull(androidIcon));
}
});
}
@Override
public void onMapReady(@NonNull MapboxMap mapboxMap) {
this.mapboxMap = mapboxMap;
Bitmap carBitmap = BitmapUtils.getBitmapFromDrawable(
getResources().getDrawable(R.drawable.ic_directions_car_black));
// marker source
markerCollection = FeatureCollection.fromFeatures(new Feature[] {
Feature.fromGeometry(Point.fromLngLat(4.91638, 52.35673), featureProperties("1", "Android")),
Feature.fromGeometry(Point.fromLngLat(4.91638, 52.34673), featureProperties("2", "Car"))
});
markerSource = new GeoJsonSource(MARKER_SOURCE, markerCollection);
// marker layer
markerSymbolLayer = new SymbolLayer(MARKER_LAYER, MARKER_SOURCE)
.withProperties(
iconImage(get(TITLE_FEATURE_PROPERTY)),
iconIgnorePlacement(true),
iconAllowOverlap(true),
iconSize(switchCase(toBool(get(SELECTED_FEATURE_PROPERTY)), literal(1.5f), literal(1.0f))),
iconAnchor(Property.ICON_ANCHOR_BOTTOM),
iconColor(Color.BLUE),
textField(TEXT_FIELD_EXPRESSION),
textFont(NORMAL_FONT_STACK),
textColor(Color.BLUE),
textAllowOverlap(true),
textIgnorePlacement(true),
textAnchor(Property.TEXT_ANCHOR_TOP),
textSize(10f)
);
// mapbox sign layer
Source mapboxSignSource = new GeoJsonSource(MAPBOX_SIGN_SOURCE, Point.fromLngLat(4.91638, 52.3510));
mapboxSignSymbolLayer = new SymbolLayer(MAPBOX_SIGN_LAYER, MAPBOX_SIGN_SOURCE);
shuffleMapboxSign();
// number format layer
Source numberFormatSource = new GeoJsonSource(NUMBER_FORMAT_SOURCE, Point.fromLngLat(4.92756, 52.3516));
numberFormatSymbolLayer = new SymbolLayer(NUMBER_FORMAT_LAYER, NUMBER_FORMAT_SOURCE);
numberFormatSymbolLayer.setProperties(
textField(
numberFormat(123.456789, locale("nl-NL"), currency("EUR"))
)
);
mapboxMap.setStyle(new Style.Builder()
.fromUri("asset://streets.json")
.withImage("Car", Objects.requireNonNull(carBitmap), false)
.withSources(markerSource, mapboxSignSource, numberFormatSource)
.withLayers(markerSymbolLayer, mapboxSignSymbolLayer, numberFormatSymbolLayer)
);
// Set a click-listener so we can manipulate the map
mapboxMap.addOnMapClickListener(SymbolLayerActivity.this);
}
@Override
public boolean onMapClick(@NonNull LatLng point) {
// Query which features are clicked
PointF screenLoc = mapboxMap.getProjection().toScreenLocation(point);
List<Feature> markerFeatures = mapboxMap.queryRenderedFeatures(screenLoc, MARKER_LAYER);
if (!markerFeatures.isEmpty()) {
for (Feature feature : Objects.requireNonNull(markerCollection.features())) {
if (feature.getStringProperty(ID_FEATURE_PROPERTY)
.equals(markerFeatures.get(0).getStringProperty(ID_FEATURE_PROPERTY))) {
// use DDS
boolean selected = feature.getBooleanProperty(SELECTED_FEATURE_PROPERTY);
feature.addBooleanProperty(SELECTED_FEATURE_PROPERTY, !selected);
// validate symbol flicker regression for #13407
markerSymbolLayer.setProperties(iconOpacity(match(
get(ID_FEATURE_PROPERTY), literal(1.0f),
stop(feature.getStringProperty("id"), selected ? 0.3f : 1.0f)
)));
}
}
markerSource.setGeoJson(markerCollection);
} else {
List<Feature> mapboxSignFeatures = mapboxMap.queryRenderedFeatures(screenLoc, MAPBOX_SIGN_LAYER);
if (!mapboxSignFeatures.isEmpty()) {
shuffleMapboxSign();
}
}
return false;
}
private void toggleTextSize() {
if (markerSymbolLayer != null) {
Number size = markerSymbolLayer.getTextSize().getValue();
if (size != null) {
markerSymbolLayer.setProperties((float) size > 10 ? textSize(10f) : textSize(20f));
}
}
}
private void toggleTextField() {
if (markerSymbolLayer != null) {
if (TEXT_FIELD_EXPRESSION.equals(markerSymbolLayer.getTextField().getExpression())) {
markerSymbolLayer.setProperties(textField("āA"));
} else {
markerSymbolLayer.setProperties(textField(TEXT_FIELD_EXPRESSION));
}
}
}
private void toggleTextFont() {
if (markerSymbolLayer != null) {
if (Arrays.equals(markerSymbolLayer.getTextFont().getValue(), NORMAL_FONT_STACK)) {
markerSymbolLayer.setProperties(textFont(BOLD_FONT_STACK));
} else {
markerSymbolLayer.setProperties(textFont(NORMAL_FONT_STACK));
}
}
}
private void shuffleMapboxSign() {
if (mapboxSignSymbolLayer != null) {
mapboxSignSymbolLayer.setProperties(
textField(
format(
formatEntry("M", formatFontScale(2)),
getRandomColorEntryForString("a"),
getRandomColorEntryForString("p"),
getRandomColorEntryForString("b"),
getRandomColorEntryForString("o"),
getRandomColorEntryForString("x")
)
),
textColor(Color.BLACK),
textFont(BOLD_FONT_STACK),
textSize(25f),
textRotationAlignment(Property.TEXT_ROTATION_ALIGNMENT_MAP)
);
}
}
private Expression.FormatEntry getRandomColorEntryForString(@NonNull String string) {
return formatEntry(string,
formatTextColor(
rgb(
random.nextInt(256),
random.nextInt(256),
random.nextInt(256)
)
));
}
private JsonObject featureProperties(@NonNull String id, @NonNull String title) {
JsonObject object = new JsonObject();
object.add(ID_FEATURE_PROPERTY, new JsonPrimitive(id));
object.add(TITLE_FEATURE_PROPERTY, new JsonPrimitive(title));
object.add(SELECTED_FEATURE_PROPERTY, new JsonPrimitive(false));
return object;
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
public void onDestroy() {
super.onDestroy();
if (mapboxMap != null) {
mapboxMap.removeOnMapClickListener(this);
}
mapView.onDestroy();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_symbol_layer, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_toggle_text_size:
toggleTextSize();
return true;
case R.id.action_toggle_text_field:
toggleTextField();
return true;
case R.id.action_toggle_text_font:
toggleTextFont();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}

View File

@@ -0,0 +1,199 @@
package com.mapbox.mapboxsdk.testapp.activity.style;
import android.graphics.PointF;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import com.google.gson.JsonObject;
import com.mapbox.geojson.Feature;
import com.mapbox.geojson.FeatureCollection;
import com.mapbox.geojson.Point;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.style.layers.Property;
import com.mapbox.mapboxsdk.style.layers.SymbolLayer;
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import com.mapbox.mapboxsdk.testapp.R;
import timber.log.Timber;
import java.util.List;
import static com.mapbox.mapboxsdk.style.expressions.Expression.get;
import static com.mapbox.mapboxsdk.style.expressions.Expression.literal;
import static com.mapbox.mapboxsdk.style.expressions.Expression.step;
import static com.mapbox.mapboxsdk.style.expressions.Expression.stop;
import static com.mapbox.mapboxsdk.style.expressions.Expression.switchCase;
import static com.mapbox.mapboxsdk.style.expressions.Expression.zoom;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAllowOverlap;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconSize;
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility;
/**
* Test activity showcasing changing the icon with a zoom function and adding selection state to a SymbolLayer.
*/
public class ZoomFunctionSymbolLayerActivity extends AppCompatActivity {
private static final String LAYER_ID = "symbolLayer";
private static final String SOURCE_ID = "poiSource";
private static final String BUS_MAKI_ICON_ID = "bus";
private static final String CAFE_MAKI_ICON_ID = "cafe-11";
private static final String KEY_PROPERTY_SELECTED = "selected";
private static final float ZOOM_STOP_MAX_VALUE = 12.0f;
private MapView mapView;
private MapboxMap mapboxMap;
private GeoJsonSource source;
private SymbolLayer layer;
private boolean isInitialPosition = true;
private boolean isSelected = false;
private boolean isShowingSymbolLayer = true;
private MapboxMap.OnMapClickListener mapClickListener = new MapboxMap.OnMapClickListener() {
@Override
public boolean onMapClick(@NonNull LatLng point) {
PointF screenPoint = mapboxMap.getProjection().toScreenLocation(point);
List<Feature> featureList = mapboxMap.queryRenderedFeatures(screenPoint, LAYER_ID);
if (!featureList.isEmpty()) {
Feature feature = featureList.get(0);
boolean selectedNow = feature.getBooleanProperty(KEY_PROPERTY_SELECTED);
isSelected = !selectedNow;
updateSource(mapboxMap.getStyle());
} else {
Timber.e("No features found");
}
return true;
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_zoom_symbol_layer);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(map -> {
mapboxMap = map;
map.setStyle(Style.MAPBOX_STREETS, style -> {
updateSource(style);
addLayer(style);
map.addOnMapClickListener(mapClickListener);
});
});
}
private void updateSource(Style style) {
FeatureCollection featureCollection = createFeatureCollection();
if (source != null) {
source.setGeoJson(featureCollection);
} else {
source = new GeoJsonSource(SOURCE_ID, featureCollection);
style.addSource(source);
}
}
private void toggleSymbolLayerVisibility() {
layer.setProperties(
visibility(isShowingSymbolLayer ? Property.NONE : Property.VISIBLE)
);
isShowingSymbolLayer = !isShowingSymbolLayer;
}
private FeatureCollection createFeatureCollection() {
Point point = isInitialPosition
? Point.fromLngLat(-74.01618140, 40.701745)
: Point.fromLngLat(-73.988097, 40.749864);
JsonObject properties = new JsonObject();
properties.addProperty(KEY_PROPERTY_SELECTED, isSelected);
Feature feature = Feature.fromGeometry(point, properties);
return FeatureCollection.fromFeatures(new Feature[] {feature});
}
private void addLayer(Style style) {
layer = new SymbolLayer(LAYER_ID, SOURCE_ID);
layer.setProperties(
iconImage(
step(zoom(), literal(BUS_MAKI_ICON_ID),
stop(ZOOM_STOP_MAX_VALUE, CAFE_MAKI_ICON_ID)
)
),
iconSize(
switchCase(
get(KEY_PROPERTY_SELECTED), literal(3.0f),
literal(1.0f)
)
),
iconAllowOverlap(true)
);
style.addLayer(layer);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_symbols, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (mapboxMap != null) {
if (item.getItemId() == R.id.menu_action_change_location) {
isInitialPosition = !isInitialPosition;
updateSource(mapboxMap.getStyle());
} else if (item.getItemId() == R.id.menu_action_toggle_source) {
toggleSymbolLayerVisibility();
}
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
public void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
}

View File

@@ -0,0 +1,189 @@
package com.mapbox.mapboxsdk.testapp.activity.telemetry;
import android.app.ActivityManager;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.WindowManager;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.module.http.HttpRequestUtil;
import com.mapbox.mapboxsdk.testapp.R;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import timber.log.Timber;
/**
* Test activity showcasing gathering performance measurement data.
*/
public class PerformanceMeasurementActivity extends AppCompatActivity {
private MapView mapView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_map_simple);
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
EventListener eventListener = new EventListener();
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.eventListener(eventListener)
.build();
HttpRequestUtil.setOkHttpClient(okHttpClient);
mapView.getMapAsync(mapboxMap -> mapboxMap.setStyle(
new Style.Builder().fromUri(Style.MAPBOX_STREETS)));
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
@Override
protected void onDestroy() {
HttpRequestUtil.setOkHttpClient(null);
super.onDestroy();
mapView.onDestroy();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
private static void triggerPerformanceEvent(String style, long elapsed) {
List<Attribute<String>> attributes = new ArrayList<>();
attributes.add(
new Attribute<>("style_id", style));
attributes.add(
new Attribute<>("test_perf_event", "true"));
List<Attribute<Long>> counters = new ArrayList();
counters.add(new Attribute<>("elapsed", elapsed));
JsonObject metaData = new JsonObject();
metaData.addProperty("os", "android");
metaData.addProperty("manufacturer", Build.MANUFACTURER);
metaData.addProperty("brand", Build.BRAND);
metaData.addProperty("device", Build.MODEL);
metaData.addProperty("version", Build.VERSION.RELEASE);
metaData.addProperty("abi", Build.CPU_ABI);
metaData.addProperty("country", Locale.getDefault().getISO3Country());
metaData.addProperty("ram", getRam());
metaData.addProperty("screenSize", getWindowSize());
Gson gson = new Gson();
Bundle bundle = new Bundle();
bundle.putString("attributes", gson.toJson(attributes));
bundle.putString("counters", gson.toJson(counters));
bundle.putString("metadata", metaData.toString());
Mapbox.getTelemetry().onPerformanceEvent(bundle);
}
private static String getRam() {
ActivityManager actManager =
(ActivityManager) Mapbox.getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo();
actManager.getMemoryInfo(memInfo);
return String.valueOf(memInfo.totalMem);
}
private static String getWindowSize() {
WindowManager windowManager =
(WindowManager) Mapbox.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
Display display = windowManager.getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
int width = metrics.widthPixels;
int height = metrics.heightPixels;
return "{" + width + "," + height + "}";
}
private static class EventListener extends okhttp3.EventListener {
private Map<String, Long> startTimes = new HashMap<>();
@Override
public void callStart(Call call) {
String url = call.request().url().toString();
startTimes.put(url, System.nanoTime());
super.callStart(call);
Timber.e("callStart: %s", url);
}
@Override
public void callEnd(Call call) {
String url = call.request().url().toString();
Timber.e("callEnd: %s", url);
Long start = startTimes.get(url);
if (start != null) {
long elapsed = System.nanoTime() - start;
triggerPerformanceEvent(url.substring(0, url.indexOf('?')), elapsed);
startTimes.remove(start);
Timber.e("callEnd: %s took %d", url, elapsed);
}
super.callEnd(call);
}
}
private static class Attribute<T> {
private String name;
private T value;
Attribute(String name, T value) {
this.name = name;
this.value = value;
}
}
}

View File

@@ -0,0 +1,148 @@
package com.mapbox.mapboxsdk.testapp.activity.textureview;
import android.animation.ObjectAnimator;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.widget.TextView;
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.Style;
import com.mapbox.mapboxsdk.testapp.R;
import java.util.Locale;
/**
* Test animating a {@link android.view.TextureView} backed map.
*/
public class TextureViewAnimationActivity extends AppCompatActivity {
private MapView mapView;
private MapboxMap mapboxMap;
private Handler handler;
private Runnable delayed;
private static LatLng[] PLACES = {
new LatLng(37.7749, -122.4194), // SF
new LatLng(38.9072, -77.0369), // DC
new LatLng(52.3702, 4.8952), // AMS
new LatLng(60.1699, 24.9384), // HEL
new LatLng(-13.1639, -74.2236), // AYA
new LatLng(52.5200, 13.4050), // BER
new LatLng(12.9716, 77.5946), // BAN
new LatLng(31.2304, 121.4737) // SHA
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_textureview_animate);
handler = new Handler(getMainLooper());
setupToolbar();
setupMapView(savedInstanceState);
}
private void setupToolbar() {
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
}
}
private void setupMapView(Bundle savedInstanceState) {
mapView = (MapView) findViewById(R.id.mapView);
mapView.getMapAsync(mapboxMap -> {
TextureViewAnimationActivity.this.mapboxMap = mapboxMap;
mapboxMap.setStyle(Style.MAPBOX_STREETS);
setFpsView(mapboxMap);
// Animate the map view
ObjectAnimator animation = ObjectAnimator.ofFloat(mapView, "rotationY", 0.0f, 360f);
animation.setDuration(3600);
animation.setRepeatCount(ObjectAnimator.INFINITE);
animation.start();
// Start an animation on the map as well
flyTo(mapboxMap, 0, 14);
});
}
private void flyTo(final MapboxMap mapboxMap, final int place, final double zoom) {
mapboxMap.animateCamera(
CameraUpdateFactory.newLatLngZoom(PLACES[place], zoom),
10000,
new MapboxMap.CancelableCallback() {
@Override
public void onCancel() {
delayed = () -> {
delayed = null;
flyTo(mapboxMap, place, zoom);
};
handler.postDelayed(delayed, 2000);
}
@Override
public void onFinish() {
flyTo(mapboxMap, place == (PLACES.length - 1) ? 0 : place + 1, zoom);
}
});
}
private void setFpsView(MapboxMap mapboxMap) {
final TextView fpsView = (TextView) findViewById(R.id.fpsView);
mapboxMap.setOnFpsChangedListener(fps -> fpsView.setText(String.format(Locale.US, "FPS: %4.2f", fps)));
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
if (handler != null && delayed != null) {
handler.removeCallbacks(delayed);
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}

View File

@@ -0,0 +1,26 @@
package com.mapbox.mapboxsdk.testapp.activity.textureview;
import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.testapp.activity.maplayout.DebugModeActivity;
import com.mapbox.mapboxsdk.testapp.utils.NavUtils;
/**
* Test activity showcasing the different debug modes and allows to cycle between the default map styles.
*/
public class TextureViewDebugModeActivity extends DebugModeActivity implements OnMapReadyCallback {
@Override
protected MapboxMapOptions setupMapboxMapOptions() {
MapboxMapOptions mapboxMapOptions = super.setupMapboxMapOptions();
mapboxMapOptions.textureMode(true);
return mapboxMapOptions;
}
@Override
public void onBackPressed() {
// activity uses singleInstance for testing purposes
// code below provides a default navigation when using the app
NavUtils.navigateHome(this);
}
}

View File

@@ -0,0 +1,103 @@
package com.mapbox.mapboxsdk.testapp.activity.textureview;
import android.os.Bundle;
import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.testapp.R;
/**
* Test resizing a {@link android.view.TextureView} backed map on the fly.
*/
public class TextureViewResizeActivity extends AppCompatActivity {
private MapView mapView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_textureview_resize);
setupToolbar();
setupMapView(savedInstanceState);
setupFab();
}
private void setupToolbar() {
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
}
}
private void setupMapView(Bundle savedInstanceState) {
mapView = findViewById(R.id.mapView);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this::setupMap);
}
private void setupMap(MapboxMap mapboxMap) {
mapboxMap.setStyle(Style.MAPBOX_STREETS);
}
private void setupFab() {
FloatingActionButton fabDebug = findViewById(R.id.fabResize);
fabDebug.setOnClickListener(view -> {
if (mapView != null) {
View parent = findViewById(R.id.coordinator_layout);
int width = parent.getWidth() == mapView.getWidth() ? parent.getWidth() / 2 : parent.getWidth();
int height = parent.getHeight() == mapView.getHeight() ? parent.getHeight() / 2 : parent.getHeight();
mapView.setLayoutParams(new CoordinatorLayout.LayoutParams(width, height));
}
});
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}

View File

@@ -0,0 +1,108 @@
package com.mapbox.mapboxsdk.testapp.activity.textureview;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapView;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.utils.ResourceUtils;
import timber.log.Timber;
import java.io.IOException;
/**
* Example showcasing how to create a TextureView with a transparent background.
*/
public class TextureViewTransparentBackgroundActivity extends AppCompatActivity {
private MapView mapView;
private MapboxMap mapboxMap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_textureview_transparent);
setupBackground();
setupMapView(savedInstanceState);
}
private void setupBackground() {
ImageView imageView = findViewById(R.id.imageView);
imageView.setImageResource(R.drawable.water);
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
}
private void setupMapView(Bundle savedInstanceState) {
MapboxMapOptions mapboxMapOptions = MapboxMapOptions.createFromAttributes(this, null);
mapboxMapOptions.translucentTextureSurface(true);
mapboxMapOptions.textureMode(true);
mapboxMapOptions.camera(new CameraPosition.Builder()
.zoom(2)
.target(new LatLng(48.507879, 8.363795))
.build()
);
mapView = new MapView(this, mapboxMapOptions);
mapView.onCreate(savedInstanceState);
mapView.getMapAsync(this::initMap);
((ViewGroup) findViewById(R.id.coordinator_layout)).addView(mapView);
}
private void initMap(MapboxMap mapboxMap) {
try {
mapboxMap.setStyle(
new Style.Builder().fromJson(ResourceUtils.readRawResource(this, R.raw.no_bg_style))
);
} catch (IOException exception) {
Timber.e(exception);
}
}
@Override
protected void onStart() {
super.onStart();
mapView.onStart();
}
@Override
protected void onResume() {
super.onResume();
mapView.onResume();
}
@Override
protected void onPause() {
super.onPause();
mapView.onPause();
}
@Override
protected void onStop() {
super.onStop();
mapView.onStop();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mapView.onSaveInstanceState(outState);
}
@Override
protected void onDestroy() {
super.onDestroy();
mapView.onDestroy();
}
@Override
public void onLowMemory() {
super.onLowMemory();
mapView.onLowMemory();
}
}

View File

@@ -0,0 +1,125 @@
package com.mapbox.mapboxsdk.testapp.activity.turf
import android.graphics.Color
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.widget.SeekBar
import com.mapbox.geojson.Point
import com.mapbox.mapboxsdk.camera.CameraPosition
import com.mapbox.mapboxsdk.geometry.LatLng
import com.mapbox.mapboxsdk.maps.Style
import com.mapbox.mapboxsdk.style.expressions.Expression.*
import com.mapbox.mapboxsdk.style.layers.FillLayer
import com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillColor
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource
import com.mapbox.mapboxsdk.testapp.R
import com.mapbox.turf.TurfTransformation
import kotlinx.android.synthetic.main.activity_physical_circle.*
/**
* An Activity that showcases how to create a Circle with radius expressed in physical units using a FillLayer.
*/
class PhysicalUnitCircleActivity : AppCompatActivity(), SeekBar.OnSeekBarChangeListener {
companion object {
const val LAYER_ID = "circle-id"
const val SOURCE_ID = "circle-id"
const val LATITUDE = 22.928207
const val LONGITUDE = 15.0155543
const val ZOOM = 10.0
}
private lateinit var source: GeoJsonSource
private var steps: Int = 10
private var radius: Double = 9000.0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_physical_circle)
mapView.onCreate(savedInstanceState)
mapView.getMapAsync { mapboxMap ->
mapboxMap.cameraPosition = CameraPosition.Builder()
.target(LatLng(LATITUDE, LONGITUDE))
.zoom(ZOOM)
.build()
source = GeoJsonSource(SOURCE_ID, TurfTransformation.circle(
Point.fromLngLat(LONGITUDE, LATITUDE), 9000.0, 10, "meters")
)
stepsBar.setOnSeekBarChangeListener(this)
radiusBar.setOnSeekBarChangeListener(this)
mapboxMap.setStyle(Style.Builder()
.fromUri(Style.SATELLITE_STREETS)
.withLayer(FillLayer(LAYER_ID, SOURCE_ID).withProperties(fillColor(interpolate(
exponential(0.5f), zoom(),
stop(8, color(Color.RED)),
stop(12, color(Color.BLUE)),
stop(16, color(Color.GREEN))
))))
.withSource(source)
)
}
}
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
seekBar?.let {
if (it.id == stepsBar.id) {
steps = progress
} else {
radius = progress.toDouble()
}
source.setGeoJson(TurfTransformation.circle(
Point.fromLngLat(LONGITUDE, LATITUDE), radius, steps, "meters")
)
}
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
// no-op
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
// no-op
}
override fun onStart() {
super.onStart()
mapView.onStart()
}
override fun onResume() {
super.onResume()
mapView.onResume()
}
override fun onPause() {
super.onPause()
mapView.onPause()
}
override fun onStop() {
super.onStop()
mapView.onStop()
}
override fun onLowMemory() {
super.onLowMemory()
mapView.onLowMemory()
}
override fun onDestroy() {
super.onDestroy()
mapView.onDestroy()
}
override fun onSaveInstanceState(outState: Bundle?) {
super.onSaveInstanceState(outState)
outState?.let {
mapView.onSaveInstanceState(it)
}
}
}

View File

@@ -0,0 +1,61 @@
package com.mapbox.mapboxsdk.testapp.adapter;
import android.graphics.Typeface;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.mapbox.mapboxsdk.testapp.R;
import com.mapbox.mapboxsdk.testapp.model.activity.Feature;
import com.mapbox.mapboxsdk.testapp.utils.FontCache;
import java.util.List;
/**
* Adapter used for FeatureOverviewActivity.
* <p>
* Adapts a Feature to a visual representation to be shown in a RecyclerView.
* </p>
*/
public class FeatureAdapter extends RecyclerView.Adapter<FeatureAdapter.ViewHolder> {
private List<Feature> features;
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView labelView;
public TextView descriptionView;
public ViewHolder(View view) {
super(view);
Typeface typeface = FontCache.get("Roboto-Regular.ttf", view.getContext());
labelView = (TextView) view.findViewById(R.id.nameView);
labelView.setTypeface(typeface);
descriptionView = (TextView) view.findViewById(R.id.descriptionView);
descriptionView.setTypeface(typeface);
}
}
public FeatureAdapter(List<Feature> features) {
this.features = features;
}
@Override
public FeatureAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_main_feature, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.labelView.setText(features.get(position).getLabel());
holder.descriptionView.setText(features.get(position).getDescription());
}
@Override
public int getItemCount() {
return features.size();
}
}

View File

@@ -0,0 +1,174 @@
package com.mapbox.mapboxsdk.testapp.adapter;
import android.content.Context;
import android.support.annotation.IdRes;
import android.support.annotation.LayoutRes;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.mapbox.mapboxsdk.testapp.utils.FontCache;
import java.util.Arrays;
public class FeatureSectionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int SECTION_TYPE = 0;
private final Context context;
private final SparseArray<Section> sections;
private final RecyclerView.Adapter adapter;
@LayoutRes
private final int sectionRes;
@IdRes
private final int textRes;
private boolean valid = true;
public FeatureSectionAdapter(Context ctx, int sectionResourceId, int textResourceId,
RecyclerView.Adapter baseAdapter) {
context = ctx;
sectionRes = sectionResourceId;
textRes = textResourceId;
adapter = baseAdapter;
sections = new SparseArray<>();
adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
@Override
public void onChanged() {
valid = adapter.getItemCount() > 0;
notifyDataSetChanged();
}
@Override
public void onItemRangeChanged(int positionStart, int itemCount) {
valid = adapter.getItemCount() > 0;
notifyItemRangeChanged(positionStart, itemCount);
}
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
valid = adapter.getItemCount() > 0;
notifyItemRangeInserted(positionStart, itemCount);
}
@Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
valid = adapter.getItemCount() > 0;
notifyItemRangeRemoved(positionStart, itemCount);
}
});
}
public static class SectionViewHolder extends RecyclerView.ViewHolder {
public TextView title;
public SectionViewHolder(@NonNull View view, @IdRes int textRes) {
super(view);
title = (TextView) view.findViewById(textRes);
title.setTypeface(FontCache.get("Roboto-Medium.ttf", view.getContext()));
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int typeView) {
if (typeView == SECTION_TYPE) {
final View view = LayoutInflater.from(context).inflate(sectionRes, parent, false);
return new SectionViewHolder(view, textRes);
} else {
return adapter.onCreateViewHolder(parent, typeView - 1);
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder sectionViewHolder, int position) {
if (isSectionHeaderPosition(position)) {
String cleanTitle = sections.get(position).title.toString().replace("_", " ");
((SectionViewHolder) sectionViewHolder).title.setText(cleanTitle);
} else {
adapter.onBindViewHolder(sectionViewHolder, getConvertedPosition(position));
}
}
@Override
public int getItemViewType(int position) {
return isSectionHeaderPosition(position)
? SECTION_TYPE
: adapter.getItemViewType(getConvertedPosition(position)) + 1;
}
public static class Section {
int firstPosition;
int sectionedPosition;
CharSequence title;
public Section(int firstPosition, CharSequence title) {
this.firstPosition = firstPosition;
this.title = title;
}
public CharSequence getTitle() {
return title;
}
}
public void setSections(Section[] sections) {
this.sections.clear();
Arrays.sort(sections, (section, section1) -> (section.firstPosition == section1.firstPosition)
? 0
: ((section.firstPosition < section1.firstPosition) ? -1 : 1));
int offset = 0;
for (Section section : sections) {
section.sectionedPosition = section.firstPosition + offset;
this.sections.append(section.sectionedPosition, section);
++offset;
}
notifyDataSetChanged();
}
public int getConvertedPosition(int sectionedPosition) {
if (isSectionHeaderPosition(sectionedPosition)) {
return RecyclerView.NO_POSITION;
}
int offset = 0;
for (int i = 0; i < sections.size(); i++) {
if (sections.valueAt(i).sectionedPosition > sectionedPosition) {
break;
}
--offset;
}
return sectionedPosition + offset;
}
public boolean isSectionHeaderPosition(int position) {
return sections.get(position) != null;
}
@Override
public long getItemId(int position) {
return isSectionHeaderPosition(position)
? Integer.MAX_VALUE - sections.indexOfKey(position)
: adapter.getItemId(getConvertedPosition(position));
}
@Override
public int getItemCount() {
return (valid ? adapter.getItemCount() + sections.size() : 0);
}
}

Some files were not shown because too many files have changed in this diff Show More