[build] - initial commit
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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())
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 + '\''
|
||||
+ '}';
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user