summaryrefslogtreecommitdiff
path: root/platform/android/MapboxGLAndroidSDK
diff options
context:
space:
mode:
Diffstat (limited to 'platform/android/MapboxGLAndroidSDK')
-rw-r--r--platform/android/MapboxGLAndroidSDK/.gitignore2
-rw-r--r--platform/android/MapboxGLAndroidSDK/build.gradle41
-rw-r--r--platform/android/MapboxGLAndroidSDK/gradle-checkstyle.gradle1
-rw-r--r--platform/android/MapboxGLAndroidSDK/gradle-javadoc.gradle2
-rw-r--r--platform/android/MapboxGLAndroidSDK/gradle.properties5
-rw-r--r--platform/android/MapboxGLAndroidSDK/lint-baseline-local.xml37
-rw-r--r--platform/android/MapboxGLAndroidSDK/lint/lint-baseline-ci.xml44
-rw-r--r--platform/android/MapboxGLAndroidSDK/proguard-rules.pro8
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/AndroidManifest.xml1
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/TwoFingerGestureDetector.java5
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/EmptyLocationSource.java107
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/LibraryLoader.java39
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java52
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerViewOptions.java3
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubbleLayout.java106
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java48
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java3
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java51
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewOptions.java3
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java60
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdate.java10
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/GeometryConstants.java63
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java20
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java14
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java19
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/Style.java1
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/IconBitmapChangedException.java6
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidLatLngBoundsException.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidMarkerPositionException.java3
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxConfigurationException.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/TooManyIconsException.java5
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ILatLng.java18
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/IProjectedMeters.java12
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java153
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java222
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngSpan.java46
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ProjectedMeters.java45
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java31
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java33
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java111
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/package-info.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java306
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java6
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java95
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java84
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Image.java17
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/InfoWindowManager.java22
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java10
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java512
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapKeyListener.java3
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java538
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapZoomButtonController.java23
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java628
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java185
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MarkerContainer.java48
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java365
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolygonContainer.java32
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolylineContainer.java38
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java38
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ShapeAnnotationContainer.java38
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ShapeAnnotations.java13
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java10
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java60
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java73
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java80
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java142
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererRunnable.java29
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererScheduler.java13
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/egl/EGLConfigChooser.java293
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/egl/EGLConfigException.java21
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/GLSurfaceViewMapRenderer.java81
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewMapRenderer.java98
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java459
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java65
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java367
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettings.java99
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/ConnectivityReceiver.java11
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java32
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java13
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionStatus.java62
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition.java54
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnaphotUtil.java29
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshot.java63
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java367
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java31
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java1761
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/Function.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java14
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CustomLayer.java14
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Layer.java13
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java127
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java1156
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java30
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java5
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java26
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs23
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Position.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CustomGeometrySource.java203
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java11
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeometryTileProvider.java22
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/text/LocalGlyphRasterizer.java46
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/BitmapUtils.java87
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java58
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/Compare.java27
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MapFragmentUtils.java13
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml12
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/color/mapbox_material_bg_selector.xml5
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/drawable-v21/mapbox_default_bg_selector.xml9
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/mapbox_mapview_preview.jpgbin166053 -> 0 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/mapbox_infowindow_icon_bg.9.pngbin928 -> 0 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_default_bg_selector.xml6
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_attribution_list_item.xml1
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_infowindow_content.xml3
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_internal.xml4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_preview.xml52
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_view_image_marker.xml7
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values-bg/strings.xml15
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values-ca/strings.xml11
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values-es/strings.xml5
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values-fr/strings.xml15
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values-hu/strings.xml13
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values-nl/strings.xml3
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values-ru/strings.xml15
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values-uk/strings.xml15
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values-vi/strings.xml5
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml7
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values/colors.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml9
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values/strings.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values/styles.xml6
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/resources/fabric/com.mapbox.mapboxsdk.mapbox-android-sdk.properties2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java5
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java26
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java14
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/AnnotationManagerTest.java11
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcherTest.java87
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapTouchListenersTest.java95
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java10
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java47
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java1010
148 files changed, 10519 insertions, 1663 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/.gitignore b/platform/android/MapboxGLAndroidSDK/.gitignore
new file mode 100644
index 0000000000..cec211fe81
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/.gitignore
@@ -0,0 +1,2 @@
+lint-baseline.xml
+lint/lint-baseline-local.xml \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/build.gradle b/platform/android/MapboxGLAndroidSDK/build.gradle
index adbc7cad7f..32eeab138f 100644
--- a/platform/android/MapboxGLAndroidSDK/build.gradle
+++ b/platform/android/MapboxGLAndroidSDK/build.gradle
@@ -1,24 +1,19 @@
apply plugin: 'com.android.library'
dependencies {
- compile rootProject.ext.dep.supportAnnotations
- compile rootProject.ext.dep.supportV4
- compile rootProject.ext.dep.supportDesign
- compile rootProject.ext.dep.timber
- compile rootProject.ext.dep.okhttp3
- compile rootProject.ext.dep.lost
- testCompile rootProject.ext.dep.junit
- testCompile rootProject.ext.dep.mockito
-
- // Mapbox Android Services (GeoJSON support)
- compile(rootProject.ext.dep.mapboxJavaGeoJSON) {
- transitive = true
- }
-
- // Mapbox Android Services (Telemetry support)
- compile(rootProject.ext.dep.mapboxAndroidTelemetry) {
- transitive = true
+ api rootProject.ext.dep.mapboxAndroidTelemetry
+ api rootProject.ext.dep.mapboxJavaGeoJSON
+ implementation rootProject.ext.dep.supportAnnotations
+ implementation rootProject.ext.dep.supportFragmentV4
+ implementation rootProject.ext.dep.timber
+ implementation rootProject.ext.dep.okhttp3
+ compileOnly(rootProject.ext.dep.lost) {
+ exclude group: 'com.google.guava'
+ exclude group: 'com.android.support'
}
+ testImplementation rootProject.ext.dep.lost
+ testImplementation rootProject.ext.dep.junit
+ testImplementation rootProject.ext.dep.mockito
}
android {
@@ -39,11 +34,14 @@ android {
// to invoke the Java tests. When we explicitly specify an ABI of 'none', no native dependencies are
// added. When another ABI is specified explicitly, we're just going to build that ABI. In all other
// cases, all ABIs are built.
- // When invoking from the command line, set `-Pmapbox.abis=...` to only build the desired architectures.
+ //
+ // When invoking from the command line or to override the device default, set `-Pmapbox.abis=...` to
+ // only build the desired architectures.
+ //
// When building from Android Studio, gradle.properties sets `android.buildOnlyTargetAbi=true` so that
// only the architecture for the device you're running on gets built.
def abi = 'all'
- if (!project.hasProperty('android.injected.invoked.from.ide')) {
+ if (!project.hasProperty('android.injected.invoked.from.ide') || project.hasProperty("mapbox.abis")) {
// Errors when the user invokes Gradle from the command line and didn't set mapbox.abis
abi = project.getProperty("mapbox.abis")
}
@@ -114,8 +112,10 @@ android {
}
lintOptions {
+ disable 'MissingTranslation', 'TypographyQuotes', 'ObsoleteLintCustomCheck', 'MissingPermission'
+ baseline file("lint-baseline-local.xml")
checkAllWarnings true
- warningsAsErrors true
+ warningsAsErrors false
}
testOptions {
@@ -150,3 +150,4 @@ apply from: 'gradle-javadoc.gradle'
apply from: 'gradle-publish.gradle'
apply from: 'gradle-checkstyle.gradle'
apply from: 'gradle-tests-staticblockremover.gradle'
+apply from: '../gradle-lint.gradle'
diff --git a/platform/android/MapboxGLAndroidSDK/gradle-checkstyle.gradle b/platform/android/MapboxGLAndroidSDK/gradle-checkstyle.gradle
index e0bc076d3d..420ccb473a 100644
--- a/platform/android/MapboxGLAndroidSDK/gradle-checkstyle.gradle
+++ b/platform/android/MapboxGLAndroidSDK/gradle-checkstyle.gradle
@@ -16,6 +16,7 @@ task checkstyle(type: Checkstyle) {
exclude '**/style/layers/PropertyFactory.java'
exclude '**/style/layers/*Layer.java'
exclude '**/style/light/Light.java'
+ exclude '**/Expression.java' // allowing single character signature as e()
classpath = files()
ignoreFailures = false
}
diff --git a/platform/android/MapboxGLAndroidSDK/gradle-javadoc.gradle b/platform/android/MapboxGLAndroidSDK/gradle-javadoc.gradle
index eeb5e9b4d6..39372b4378 100644
--- a/platform/android/MapboxGLAndroidSDK/gradle-javadoc.gradle
+++ b/platform/android/MapboxGLAndroidSDK/gradle-javadoc.gradle
@@ -10,7 +10,7 @@ android.libraryVariants.all { variant ->
options.windowTitle("Mapbox Android SDK $VERSION_NAME Reference")
options.docTitle("Mapbox Android SDK $VERSION_NAME")
options.header("Mapbox Android SDK $VERSION_NAME Reference")
- options.bottom("© 2015–2017 Mapbox. All rights reserved.")
+ options.bottom("© 2015–2018 Mapbox. All rights reserved.")
options.links("http://docs.oracle.com/javase/7/docs/api/")
options.linksOffline("http://d.android.com/reference/", "$System.env.ANDROID_HOME/docs/reference")
options.overview("src/main/java/overview.html")
diff --git a/platform/android/MapboxGLAndroidSDK/gradle.properties b/platform/android/MapboxGLAndroidSDK/gradle.properties
index 9f555da5f8..f00eb1d77f 100644
--- a/platform/android/MapboxGLAndroidSDK/gradle.properties
+++ b/platform/android/MapboxGLAndroidSDK/gradle.properties
@@ -1,5 +1,5 @@
GROUP=com.mapbox.mapboxsdk
-VERSION_NAME=5.1.0-SNAPSHOT
+VERSION_NAME=6.0.0-SNAPSHOT
POM_DESCRIPTION=Mapbox GL Android SDK
POM_URL=https://github.com/mapbox/mapbox-gl-native
@@ -11,10 +11,11 @@ POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
POM_LICENCE_DIST=repo
POM_DEVELOPER_ID=mapbox
POM_DEVELOPER_NAME=Mapbox
-POM_NAME=Mapbox Android SDK
+POM_NAME=Mapbox Maps SDK for Android
POM_ARTIFACT_ID=mapbox-android-sdk
POM_PACKAGING=aar
# Only build native dependencies for the current ABI
# See https://code.google.com/p/android/issues/detail?id=221098#c20
android.buildOnlyTargetAbi=true
+
diff --git a/platform/android/MapboxGLAndroidSDK/lint-baseline-local.xml b/platform/android/MapboxGLAndroidSDK/lint-baseline-local.xml
new file mode 100644
index 0000000000..0a76f53505
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/lint-baseline-local.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<issues format="4" by="lint 2.3.1">
+
+ <issue
+ id="MissingTranslation"
+ message="&quot;`mapbox_attributionErrorNoBrowser`&quot; is not translated in &quot;ca&quot; (Catalan), &quot;es&quot; (Spanish), &quot;lt&quot; (Lithuanian), &quot;nl&quot; (Dutch), &quot;sv&quot; (Swedish), &quot;vi&quot; (Vietnamese)"
+ errorLine1=" &lt;string name=&quot;mapbox_attributionErrorNoBrowser&quot;>No web browser installed on device, can\&apos;t open web page.&lt;/string>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/res/values/strings.xml"
+ line="13"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="MissingTranslation"
+ message="&quot;`mapbox_telemetrySettings`&quot; is not translated in &quot;ca&quot; (Catalan), &quot;es&quot; (Spanish), &quot;lt&quot; (Lithuanian), &quot;nl&quot; (Dutch), &quot;sv&quot; (Swedish), &quot;vi&quot; (Vietnamese)"
+ errorLine1=" &lt;string name=&quot;mapbox_telemetrySettings&quot;>Telemetry Settings&lt;/string>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/res/values/strings.xml"
+ line="15"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="TypographyQuotes"
+ message="Replace straight quotes (&apos;&apos;) with directional quotes (‘’, &amp;#8216; and &amp;#8217;) ?"
+ errorLine1=" &lt;string name=&quot;mapbox_attributionTelemetryMessage&quot;>Estàs ajudant a millorar els mapes d\&apos;OpenStreetMap i de Mapbox aportant dades d\&apos;ús anònimes.&lt;/string>"
+ errorLine2=" ^">
+ <location
+ file="src/main/res/values-ca/strings.xml"
+ line="9"
+ column="55"/>
+ </issue>
+
+</issues>
diff --git a/platform/android/MapboxGLAndroidSDK/lint/lint-baseline-ci.xml b/platform/android/MapboxGLAndroidSDK/lint/lint-baseline-ci.xml
new file mode 100644
index 0000000000..fd65c9f627
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/lint/lint-baseline-ci.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- REMEMBER! First you run Lint locally you'll need to move lint-baseline-local.xml.xml file
+ generated into the lint folder and called it lint-baseline-local.xml
+ If you remove any error when running Lint locally, you'll get a warning from the command
+ line advising you to remove it from the baseline. If you remove it (remember to remove it
+ from lint-baseline-local.xml file) you should remove it too from
+ lint-baseline-ci.xml (THIS FILE) which is the only one included in the repo.
+ Eventually, it'll be removed (when we remove all current lint errors included). -->
+<issues format="4" by="lint 2.3.1">
+
+ <issue
+ id="MissingTranslation"
+ message="&quot;`mapbox_attributionErrorNoBrowser`&quot; is not translated in &quot;ca&quot; (Catalan), &quot;es&quot; (Spanish), &quot;lt&quot; (Lithuanian), &quot;nl&quot; (Dutch), &quot;sv&quot; (Swedish), &quot;vi&quot; (Vietnamese)"
+ errorLine1=" &lt;string name=&quot;mapbox_attributionErrorNoBrowser&quot;>No web browser installed on device, can\&apos;t open web page.&lt;/string>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/res/values/strings.xml"
+ line="13"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="MissingTranslation"
+ message="&quot;`mapbox_telemetrySettings`&quot; is not translated in &quot;ca&quot; (Catalan), &quot;es&quot; (Spanish), &quot;lt&quot; (Lithuanian), &quot;nl&quot; (Dutch), &quot;sv&quot; (Swedish), &quot;vi&quot; (Vietnamese)"
+ errorLine1=" &lt;string name=&quot;mapbox_telemetrySettings&quot;>Telemetry Settings&lt;/string>"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="src/main/res/values/strings.xml"
+ line="15"
+ column="13"/>
+ </issue>
+
+ <issue
+ id="TypographyQuotes"
+ message="Replace straight quotes (&apos;&apos;) with directional quotes (‘’, &amp;#8216; and &amp;#8217;) ?"
+ errorLine1=" &lt;string name=&quot;mapbox_attributionTelemetryMessage&quot;>Estàs ajudant a millorar els mapes d\&apos;OpenStreetMap i de Mapbox aportant dades d\&apos;ús anònimes.&lt;/string>"
+ errorLine2=" ^">
+ <location
+ file="src/main/res/values-ca/strings.xml"
+ line="9"
+ column="55"/>
+ </issue>
+
+</issues>
diff --git a/platform/android/MapboxGLAndroidSDK/proguard-rules.pro b/platform/android/MapboxGLAndroidSDK/proguard-rules.pro
index 8e47815451..b5a1d82c81 100644
--- a/platform/android/MapboxGLAndroidSDK/proguard-rules.pro
+++ b/platform/android/MapboxGLAndroidSDK/proguard-rules.pro
@@ -6,4 +6,10 @@
-keep class com.mapbox.mapboxsdk.** { *; }
-keep interface com.mapbox.mapboxsdk.** { *; }
-keep class com.mapbox.services.android.telemetry.** { *; }
--keep class com.mapbox.services.commons.** { *;} \ No newline at end of file
+-keep class com.mapbox.services.commons.** { *;}
+-keep class com.google.gson.** { *; }
+
+# config for okhttp 3.8.0, https://github.com/square/okhttp/pull/3354
+-dontwarn okio.**
+-dontwarn javax.annotation.Nullable
+-dontwarn javax.annotation.ParametersAreNonnullByDefault \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDK/src/main/AndroidManifest.xml
index 231e36e092..b61035a008 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/AndroidManifest.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/AndroidManifest.xml
@@ -3,6 +3,7 @@
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
<uses-feature android:name="android.hardware.wifi" android:required="false" /> <!-- Implied by ACCESS_WIFI_STATE. -->
+ <uses-feature android:name="android.hardware.location.gps" android:required="false"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/TwoFingerGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/TwoFingerGestureDetector.java
index 71fb9aa168..db492b6556 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/TwoFingerGestureDetector.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/TwoFingerGestureDetector.java
@@ -54,8 +54,7 @@ public abstract class TwoFingerGestureDetector extends BaseGestureDetector {
ViewConfiguration config = ViewConfiguration.get(context);
- // We divide edge slop by 2 to make rotation gesture happen more easily #6870
- edgeSlop = config.getScaledEdgeSlop() / 2;
+ edgeSlop = config.getScaledEdgeSlop();
}
@Override
@@ -222,4 +221,4 @@ public abstract class TwoFingerGestureDetector extends BaseGestureDetector {
return focus.y;
}
-}
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/EmptyLocationSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/EmptyLocationSource.java
new file mode 100644
index 0000000000..8ea7e61eee
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/EmptyLocationSource.java
@@ -0,0 +1,107 @@
+package com.mapbox.mapboxsdk;
+
+
+import android.location.Location;
+import android.support.annotation.Nullable;
+
+import com.mapbox.mapboxsdk.location.LocationSource;
+import com.mapbox.services.android.telemetry.location.LocationEngine;
+import com.mapbox.services.android.telemetry.location.LocationEngineListener;
+
+class EmptyLocationSource extends LocationSource {
+
+ /**
+ * Activate the location engine which will connect whichever location provider you are using. You'll need to call
+ * this before requesting user location updates using {@link LocationEngine#requestLocationUpdates()}.
+ */
+ @Override
+ public void activate() {
+ // Intentionally left empty
+ }
+
+ /**
+ * Disconnect the location engine which is useful when you no longer need location updates or requesting the users
+ * {@link LocationEngine#getLastLocation()}. Before deactivating, you'll need to stop request user location updates
+ * using {@link LocationEngine#removeLocationUpdates()}.
+ */
+ @Override
+ public void deactivate() {
+ // Intentionally left empty
+ }
+
+ /**
+ * Check if your location provider has been activated/connected. This is mainly used internally but is also useful in
+ * the rare case when you'd like to know if your location engine is connected or not.
+ *
+ * @return boolean true if the location engine has been activated/connected, else false.
+ */
+ @Override
+ public boolean isConnected() {
+ return false;
+ }
+
+ /**
+ * Returns the Last known location is the location provider is connected and location permissions are granted.
+ *
+ * @return the last known location
+ */
+ @Override
+ @Nullable
+ public Location getLastLocation() {
+ return null;
+ }
+
+ /**
+ * Request location updates to the location provider.
+ */
+ @Override
+ public void requestLocationUpdates() {
+ // Intentionally left empty
+ }
+
+ /**
+ * Dismiss ongoing location update to the location provider.
+ */
+ @Override
+ public void removeLocationUpdates() {
+ // Intentionally left empty
+ }
+
+ /**
+ * Invoked when the Location has changed.
+ *
+ * @param location the new location
+ */
+ @Override
+ public void onLocationChanged(Location location) {
+ // Intentionally left empty
+ }
+
+ /**
+ * Useful when you'd like to add a location listener to handle location connections and update events. It is important
+ * to note, that the callback will continue getting called even when your application isn't in the foreground.
+ * Therefore, it is a good idea to use {@link LocationEngine#removeLocationEngineListener(LocationEngineListener)}
+ * inside your activities {@code onStop()} method.
+ *
+ * @param listener A {@link LocationEngineListener} which you'd like to add to your location engine.
+ * @since 2.0.0
+ */
+ @Override
+ public void addLocationEngineListener(LocationEngineListener listener) {
+ // Intentionally left empty
+ }
+
+ /**
+ * If you no longer need your {@link LocationEngineListener} to be invoked with every location update, use this
+ * method to remove it. It's also important to remove your listeners before the activity is destroyed to prevent any
+ * potential memory leaks.
+ *
+ * @param listener the {@link LocationEngineListener} you'd like to remove from this {@link LocationEngine}.
+ * @return true.
+ * @since 2.0.0
+ */
+ @Override
+ public boolean removeLocationEngineListener(LocationEngineListener listener) {
+ return true;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/LibraryLoader.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/LibraryLoader.java
index 8a75176ccd..6633d5d952 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/LibraryLoader.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/LibraryLoader.java
@@ -1,15 +1,48 @@
package com.mapbox.mapboxsdk;
+import timber.log.Timber;
+
/**
- * Centralises the knowledge about "mapbox-gl" library loading.
+ * Loads the mapbox-gl shared library
+ * <p>
+ * By default uses the {@link System#loadLibrary(String)},
+ * use {@link #setLibraryLoader(LibraryLoader)} to provide an alternative library loading hook.
+ * </p>
*/
-public class LibraryLoader {
+public abstract class LibraryLoader {
+
+ private static final LibraryLoader DEFAULT = new LibraryLoader() {
+ @Override
+ public void load(String name) {
+ System.loadLibrary(name);
+ }
+ };
+
+ private static volatile LibraryLoader loader = DEFAULT;
+
+ /**
+ * Set the library loader that loads the shared library.
+ *
+ * @param libraryLoader the library loader
+ */
+ public static void setLibraryLoader(LibraryLoader libraryLoader) {
+ loader = libraryLoader;
+ }
/**
* Loads "libmapbox-gl.so" native shared library.
+ * <p>
+ * Catches UnsatisfiedLinkErrors and prints a warning to logcat.
+ * </p>
*/
public static void load() {
- System.loadLibrary("mapbox-gl");
+ try {
+ loader.load("mapbox-gl");
+ } catch (UnsatisfiedLinkError error) {
+ Timber.e(error, "Failed to load native shared library.");
+ }
}
+ public abstract void load(String name);
}
+
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java
index bc1049d146..b67b6e96f2 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java
@@ -1,6 +1,6 @@
package com.mapbox.mapboxsdk;
-import android.app.Application;
+import android.annotation.SuppressLint;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
@@ -15,22 +15,27 @@ import com.mapbox.mapboxsdk.net.ConnectivityReceiver;
import com.mapbox.services.android.telemetry.MapboxTelemetry;
import com.mapbox.services.android.telemetry.location.LocationEngine;
import com.mapbox.services.android.telemetry.location.LocationEnginePriority;
+import com.mapbox.services.android.telemetry.location.LocationEngineProvider;
+
+import timber.log.Timber;
/**
- * The entry point of the Mapbox Android SDK.
+ * The entry point to initialize the Mapbox Android SDK.
* <p>
* Obtain a reference by calling {@link #getInstance(Context, String)}. Usually this class is configured in
- * {@link Application#onCreate()} and is responsible for the active access token, application context, and
+ * Application#onCreate() and is responsible for the active access token, application context, and
* connectivity state.
* </p>
*/
@UiThread
public final class Mapbox {
+ @SuppressLint("StaticFieldLeak")
private static Mapbox INSTANCE;
private Context context;
private String accessToken;
private Boolean connected;
+ private LocationEngine locationEngine;
/**
* Get an instance of Mapbox.
@@ -46,19 +51,27 @@ public final class Mapbox {
public static synchronized Mapbox getInstance(@NonNull Context context, @NonNull String accessToken) {
if (INSTANCE == null) {
Context appContext = context.getApplicationContext();
- INSTANCE = new Mapbox(appContext, accessToken);
- LocationEngine locationEngine = LocationSource.getLocationEngine(appContext);
+ LocationEngineProvider locationEngineProvider = new LocationEngineProvider(context);
+ LocationEngine locationEngine = locationEngineProvider.obtainBestLocationEngineAvailable();
+ INSTANCE = new Mapbox(appContext, accessToken, locationEngine);
locationEngine.setPriority(LocationEnginePriority.NO_POWER);
- MapboxTelemetry.getInstance().initialize(
- appContext, accessToken, BuildConfig.MAPBOX_EVENTS_USER_AGENT, locationEngine);
+
+ try {
+ MapboxTelemetry.getInstance().initialize(
+ appContext, accessToken, BuildConfig.MAPBOX_EVENTS_USER_AGENT, locationEngine);
+ } catch (Exception exception) {
+ Timber.e(exception, "Unable to instantiate Mapbox telemetry");
+ }
+
ConnectivityReceiver.instance(appContext);
}
return INSTANCE;
}
- Mapbox(@NonNull Context context, @NonNull String accessToken) {
+ Mapbox(@NonNull Context context, @NonNull String accessToken, LocationEngine locationEngine) {
this.context = context;
this.accessToken = accessToken;
+ this.locationEngine = locationEngine;
}
/**
@@ -96,6 +109,8 @@ public final class Mapbox {
/**
* Application context
+ *
+ * @return the application context
*/
public static Context getApplicationContext() {
return INSTANCE.context;
@@ -129,4 +144,25 @@ public final class Mapbox {
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
return (activeNetwork != null && activeNetwork.isConnected());
}
+
+ /**
+ * Returns a location source instance with empty methods.
+ *
+ * @return an empty location source implementation
+ * @deprecated Replaced by {@link Mapbox#getLocationEngine()}
+ */
+ @Deprecated
+ public static LocationSource getLocationSource() {
+ return new EmptyLocationSource();
+ }
+
+
+ /**
+ * Returns the location engine used by the SDK.
+ *
+ * @return the location engine configured
+ */
+ public static LocationEngine getLocationEngine() {
+ return INSTANCE.locationEngine;
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerViewOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerViewOptions.java
index ddedf3debf..3fd2fa4ebf 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerViewOptions.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerViewOptions.java
@@ -14,7 +14,10 @@ import com.mapbox.mapboxsdk.geometry.LatLng;
*
* @param <U> Type of the marker view to be composed.
* @param <T> Type of the builder to be used for composing.
+ * @deprecated Use a {@link com.mapbox.mapboxsdk.style.layers.SymbolLayer} instead. An example of converting Android
+ * SDK views to be used as a symbol see https://github.com/mapbox/mapbox-gl-native/blob/68f32bc104422207c64da8d90e8411b138d87f04/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java
*/
+@Deprecated
public abstract class BaseMarkerViewOptions<U extends MarkerView, T extends BaseMarkerViewOptions<U, T>>
implements Parcelable {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubbleLayout.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubbleLayout.java
index 07e038c08c..c58cc310a8 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubbleLayout.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BubbleLayout.java
@@ -27,14 +27,32 @@ public class BubbleLayout extends LinearLayout {
private float strokeWidth;
private int strokeColor;
+ /**
+ * Creates an instance of bubble layout.
+ *
+ * @param context The context used to inflate this bubble layout
+ */
public BubbleLayout(Context context) {
this(context, null, 0);
}
+ /**
+ * Creates an instance of bubble layout.
+ *
+ * @param context The context used to inflate this bubble layout
+ * @param attrs The attribute set to initialise this bubble layout from
+ */
public BubbleLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
+ /**
+ * Creates an instance of bubble layout.
+ *
+ * @param context The context used to inflate this bubble layout
+ * @param attrs The attribute set to initialise this bubble layout from
+ * @param defStyleAttr The default style to apply this bubble layout with
+ */
public BubbleLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
@@ -78,10 +96,21 @@ public class BubbleLayout extends LinearLayout {
return dp * (metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT);
}
+ /**
+ * Get the arrow direction.
+ *
+ * @return the arrow direction
+ */
public ArrowDirection getArrowDirection() {
return arrowDirection;
}
+ /**
+ * Set the arrow direction.
+ *
+ * @param arrowDirection The direction of the arrow
+ * @return this
+ */
public BubbleLayout setArrowDirection(ArrowDirection arrowDirection) {
resetPadding();
this.arrowDirection = arrowDirection;
@@ -89,10 +118,21 @@ public class BubbleLayout extends LinearLayout {
return this;
}
+ /**
+ * Get the arrow width.
+ *
+ * @return the width of the arrow
+ */
public float getArrowWidth() {
return arrowWidth;
}
+ /**
+ * Set the arrow width.
+ *
+ * @param arrowWidth The width of the arrow
+ * @return this
+ */
public BubbleLayout setArrowWidth(float arrowWidth) {
resetPadding();
this.arrowWidth = arrowWidth;
@@ -100,10 +140,21 @@ public class BubbleLayout extends LinearLayout {
return this;
}
+ /**
+ * Get the arrow height
+ *
+ * @return the height of the arrow
+ */
public float getArrowHeight() {
return arrowHeight;
}
+ /**
+ * Set the arrow height.
+ *
+ * @param arrowHeight The height of the arrow
+ * @return this
+ */
public BubbleLayout setArrowHeight(float arrowHeight) {
resetPadding();
this.arrowHeight = arrowHeight;
@@ -111,10 +162,21 @@ public class BubbleLayout extends LinearLayout {
return this;
}
+ /**
+ * Get the arrow position.
+ *
+ * @return the arrow position
+ */
public float getArrowPosition() {
return arrowPosition;
}
+ /**
+ * Get the arrow position.
+ *
+ * @param arrowPosition The arrow position
+ * @return this
+ */
public BubbleLayout setArrowPosition(float arrowPosition) {
resetPadding();
this.arrowPosition = arrowPosition;
@@ -122,30 +184,63 @@ public class BubbleLayout extends LinearLayout {
return this;
}
+ /**
+ * Get the corner radius
+ *
+ * @return the corner radius
+ */
public float getCornersRadius() {
return cornersRadius;
}
+ /**
+ * Set the corner radius
+ *
+ * @param cornersRadius The corner radius
+ * @return this
+ */
public BubbleLayout setCornersRadius(float cornersRadius) {
this.cornersRadius = cornersRadius;
requestLayout();
return this;
}
+ /**
+ * Get the bubble color.
+ *
+ * @return the bubble color
+ */
public int getBubbleColor() {
return bubbleColor;
}
+ /**
+ * Set the bubble color.
+ *
+ * @param bubbleColor The buble color
+ * @return this
+ */
public BubbleLayout setBubbleColor(int bubbleColor) {
this.bubbleColor = bubbleColor;
requestLayout();
return this;
}
+ /**
+ * Get stroke width.
+ *
+ * @return the stroke width
+ */
public float getStrokeWidth() {
return strokeWidth;
}
+ /**
+ * Set the stroke width.
+ *
+ * @param strokeWidth The stroke width
+ * @return this
+ */
public BubbleLayout setStrokeWidth(float strokeWidth) {
resetPadding();
this.strokeWidth = strokeWidth;
@@ -153,10 +248,21 @@ public class BubbleLayout extends LinearLayout {
return this;
}
+ /**
+ * Get the stroke color.
+ *
+ * @return the stroke color
+ */
public int getStrokeColor() {
return strokeColor;
}
+ /**
+ * Set the stroke color.
+ *
+ * @param strokeColor The stroke color
+ * @return this
+ */
public BubbleLayout setStrokeColor(int strokeColor) {
this.strokeColor = strokeColor;
requestLayout();
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java
index 2ee17c227d..8749656e35 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java
@@ -36,7 +36,7 @@ public class Icon {
* @return The bitmap being used for the icon.
*/
public Bitmap getBitmap() {
- if (mBitmap.getConfig() != Bitmap.Config.ARGB_8888) {
+ if (mBitmap != null && mBitmap.getConfig() != Bitmap.Config.ARGB_8888) {
mBitmap = mBitmap.copy(Bitmap.Config.ARGB_8888, false);
}
return mBitmap;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java
index 57aa512401..3c9cb31211 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java
@@ -1,5 +1,6 @@
package com.mapbox.mapboxsdk.annotations;
+import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -23,7 +24,7 @@ import java.io.InputStream;
/**
* Factory for creating Icons from bitmap images.
* <p>
- * {@link Icon} is used to display bitmaps on top of the map using {@link Marker} and {@link MarkerView}.
+ * icon is used to display bitmaps on top of the map using {@link Marker} and {@link MarkerView}.
* </p>
*
* @see Icon
@@ -35,6 +36,7 @@ public final class IconFactory {
public static final String ICON_MARKERVIEW_ID = ICON_ID_PREFIX + "marker_view";
private Context context;
+ @SuppressLint("StaticFieldLeak")
private static IconFactory instance;
private Icon defaultMarker;
private Icon defaultMarkerView;
@@ -42,6 +44,12 @@ public final class IconFactory {
private int nextId = 0;
+ /**
+ * Get a single instance of IconFactory.
+ *
+ * @param context the context to derive the application context from
+ * @return the single instance of IconFactory
+ */
public static synchronized IconFactory getInstance(@NonNull Context context) {
if (instance == null) {
instance = new IconFactory(context.getApplicationContext());
@@ -71,10 +79,10 @@ public final class IconFactory {
}
/**
- * Creates an {@link Icon} from a given Bitmap image.
+ * Creates an icon from a given Bitmap image.
*
* @param bitmap image used for creating the Icon.
- * @return The {@link Icon} using the given Bitmap image.
+ * @return The icon using the given Bitmap image.
*/
public Icon fromBitmap(@NonNull Bitmap bitmap) {
if (nextId < 0) {
@@ -85,10 +93,10 @@ public final class IconFactory {
}
/**
- * Create an {@link Icon} using the resource ID of a Bitmap image.
+ * Creates an icon using the resource ID of a Bitmap image.
*
* @param resourceId The resource ID of a Bitmap image.
- * @return The {@link Icon} that was loaded from the asset or {@code null} if failed to load.
+ * @return The icon that was loaded from the asset or {@code null} if failed to load.
*/
public Icon fromResource(@DrawableRes int resourceId) {
Drawable drawable = ContextCompat.getDrawable(context, resourceId);
@@ -101,9 +109,9 @@ public final class IconFactory {
}
/**
- * Provides an {@link Icon} using the default marker icon used for {@link Marker}.
+ * Provides an icon using the default marker icon used for {@link Marker}.
*
- * @return An {@link Icon} with the default {@link Marker} icon.
+ * @return An icon with the default {@link Marker} icon.
*/
public Icon defaultMarker() {
if (defaultMarker == null) {
@@ -113,9 +121,9 @@ public final class IconFactory {
}
/**
- * Provides an {@link Icon} using the default marker icon used for {@link MarkerView}.
+ * Provides an icon using the default marker icon used for {@link MarkerView}.
*
- * @return An {@link Icon} with the default {@link MarkerView} icon.
+ * @return An icon with the default {@link MarkerView} icon.
*/
public Icon defaultMarkerView() {
if (defaultMarkerView == null) {
@@ -130,10 +138,10 @@ public final class IconFactory {
}
/**
- * Creates an {@link Icon} using the name of a Bitmap image in the assets directory.
+ * Creates an Icon using the name of a Bitmap image in the assets directory.
*
* @param assetName The name of a Bitmap image in the assets directory.
- * @return The {@link Icon} that was loaded from the asset or {@code null} if failed to load.
+ * @return The Icon that was loaded from the asset or null if failed to load.
*/
public Icon fromAsset(@NonNull String assetName) {
InputStream is;
@@ -146,11 +154,10 @@ public final class IconFactory {
}
/**
- * Creates an {@link Icon} using the absolute file path of a Bitmap image.
+ * Creates an Icon using the absolute file path of a Bitmap image.
*
* @param absolutePath The absolute path of the Bitmap image.
- * @return The {@link Icon} that was loaded from the absolute path or {@code null} if failed to
- * load.
+ * @return The Icon that was loaded from the absolute path or null if failed to load.
*/
public Icon fromPath(@NonNull String absolutePath) {
Bitmap bitmap = BitmapFactory.decodeFile(absolutePath, options);
@@ -158,11 +165,11 @@ public final class IconFactory {
}
/**
- * Create an {@link Icon} using the name of a Bitmap image file located in the internal storage.
- * In particular, this calls {@link Context#openFileInput(String)}.
+ * Create an Icon using the name of a Bitmap image file located in the internal storage.
+ * In particular, this calls Context#openFileInput(String).
*
* @param fileName The name of the Bitmap image file.
- * @return The {@link Icon} that was loaded from the asset or {@code null} if failed to load.
+ * @return The Icon that was loaded from the asset or null if failed to load.
* @see <a href="https://developer.android.com/guide/topics/data/data-storage.html#filesInternal">
* Using the Internal Storage</a>
*/
@@ -177,12 +184,11 @@ public final class IconFactory {
}
/**
- * Create an {@link Icon} using a previously created icon identifier along with a provided
- * Bitmap.
+ * Create an Icon using a previously created icon identifier along with a provided Bitmap.
*
- * @param iconId The {@link Icon} identifier you'd like to recreate.
+ * @param iconId The Icon identifier you'd like to recreate.
* @param bitmap a Bitmap used to replace the current one.
- * @return The {@link Icon} using the new Bitmap.
+ * @return The Icon using the new Bitmap.
*/
public static Icon recreate(@NonNull String iconId, @NonNull Bitmap bitmap) {
return new Icon(iconId, bitmap);
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java
index 56e8cc4ce2..eb82c7bf53 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java
@@ -24,7 +24,10 @@ import com.mapbox.mapboxsdk.maps.MapboxMap;
* used with event listeners to bring up info windows. An {@link InfoWindow} is displayed by default
* when either a title or snippet is provided.
* </p>
+ * @deprecated Use a {@link com.mapbox.mapboxsdk.style.layers.SymbolLayer} instead. An example of converting Android
+ * SDK views to be used as a symbol see https://github.com/mapbox/mapbox-gl-native/blob/68f32bc104422207c64da8d90e8411b138d87f04/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java
*/
+@Deprecated
public class MarkerView extends Marker {
private MarkerViewManager markerViewManager;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java
index bb51f3bfc2..8304d0e6ed 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java
@@ -10,6 +10,7 @@ import android.support.v4.util.LongSparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
import android.widget.ImageView;
import com.mapbox.mapboxsdk.R;
@@ -29,10 +30,22 @@ import java.util.Map;
* <p>
* This class is responsible for managing a {@link MarkerView} item.
* </p>
+ * @deprecated Use a {@link com.mapbox.mapboxsdk.style.layers.SymbolLayer} instead. An example of converting Android
+ * SDK views to be used as a symbol see https://github.com/mapbox/mapbox-gl-native/blob/68f32bc104422207c64da8d90e8411b138d87f04/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java
*/
+@Deprecated
public class MarkerViewManager implements MapView.OnMapChangedListener {
private final ViewGroup markerViewContainer;
+ private final ViewTreeObserver.OnPreDrawListener markerViewPreDrawObserver =
+ new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ invalidateViewMarkersInVisibleRegion();
+ markerViewContainer.getViewTreeObserver().removeOnPreDrawListener(markerViewPreDrawObserver);
+ return false;
+ }
+ };
private final Map<MarkerView, View> markerViewMap = new HashMap<>();
private final LongSparseArray<OnMarkerViewAddedListener> markerViewAddedListenerMap = new LongSparseArray<>();
private final List<MapboxMap.MarkerViewAdapter> markerViewAdapters = new ArrayList<>();
@@ -125,6 +138,12 @@ public class MarkerViewManager implements MapView.OnMapChangedListener {
}
}
+ /**
+ * Set the rotation of a MarkerView to a given rotation value.
+ *
+ * @param marker The MarkerView to change its rotation value
+ * @param rotation The rotation value
+ */
public void setRotation(@NonNull MarkerView marker, float rotation) {
View convertView = markerViewMap.get(marker);
if (convertView != null) {
@@ -180,14 +199,16 @@ public class MarkerViewManager implements MapView.OnMapChangedListener {
PointF point = mapboxMap.getProjection().toScreenLocation(marker.getPosition());
if (marker.getOffsetX() == MapboxConstants.UNMEASURED) {
// ensure view is measured first
- if (marker.getWidth() == 0) {
- convertView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
- if (convertView.getMeasuredWidth() != 0) {
- marker.setWidth(convertView.getMeasuredWidth());
- marker.setHeight(convertView.getMeasuredHeight());
- }
+ // #6805 invalidate marker views to ensure convertView width and height
+ // values are properly measured and up to date
+ if (marker.getWidth() == 0 && marker.isVisible()) {
+ convertView.getViewTreeObserver().addOnPreDrawListener(markerViewPreDrawObserver);
}
}
+
+ marker.setWidth(convertView.getWidth());
+ marker.setHeight(convertView.getHeight());
+
if (marker.getWidth() != 0) {
int x = (int) (marker.getAnchorU() * marker.getWidth());
int y = (int) (marker.getAnchorV() * marker.getHeight());
@@ -532,10 +553,11 @@ public class MarkerViewManager implements MapView.OnMapChangedListener {
}
/**
- * When the provided {@link MarkerView} is clicked on by a user, we check if a custom click
- * event has been created and if not, display a {@link InfoWindow}.
+ * When the provided MarkerView is clicked on by a user, we check if a custom click
+ * event has been created and if not, display a InfoWindow.
*
- * @param markerView that the click event occurred.
+ * @param markerView that the click event occurred
+ * @return true if the marker view click has been handled, false if not
*/
public boolean onClickMarkerView(MarkerView markerView) {
boolean clickHandled = false;
@@ -551,18 +573,13 @@ public class MarkerViewManager implements MapView.OnMapChangedListener {
clickHandled = onMarkerViewClickListener.onMarkerClick(markerView, view, adapter);
}
- if (!clickHandled) {
- ensureInfoWindowOffset(markerView);
- select(markerView, view, adapter);
- }
-
return clickHandled;
}
/**
- * Handles the {@link MarkerView}'s info window offset.
+ * Handles the MarkerView info window offset.
*
- * @param marker that we are ensuring info window offset.
+ * @param marker that we are ensuring info window offset
*/
public void ensureInfoWindowOffset(MarkerView marker) {
View view = null;
@@ -612,7 +629,7 @@ public class MarkerViewManager implements MapView.OnMapChangedListener {
}
/**
- * Default MarkerViewAdapter used for base class of {@link MarkerView} to adapt a MarkerView to
+ * Default MarkerViewAdapter used for base class of MarkerView to adapt a MarkerView to
* an ImageView.
*/
private static class ImageMarkerViewAdapter extends MapboxMap.MarkerViewAdapter<MarkerView> {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewOptions.java
index 2d829537fc..79c72e5f70 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewOptions.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewOptions.java
@@ -12,7 +12,10 @@ import com.mapbox.mapboxsdk.geometry.LatLng;
* <p>
* Do not extend this class directly but extend {@link BaseMarkerViewOptions} instead.
* </p>
+ * @deprecated Use a {@link com.mapbox.mapboxsdk.style.layers.SymbolLayer} instead. An example of converting Android
+ * SDK views to be used as a symbol see https://github.com/mapbox/mapbox-gl-native/blob/68f32bc104422207c64da8d90e8411b138d87f04/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java
*/
+@Deprecated
public class MarkerViewOptions extends BaseMarkerViewOptions<MarkerView, MarkerViewOptions> {
private MarkerView marker;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java
index 66c261f1d0..c2f19072db 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java
@@ -3,6 +3,7 @@ package com.mapbox.mapboxsdk.camera;
import android.content.res.TypedArray;
import android.os.Parcel;
import android.os.Parcelable;
+import android.support.annotation.FloatRange;
import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
@@ -166,14 +167,14 @@ public final class CameraPosition implements Parcelable {
private double zoom = -1;
/**
- * Creates an empty builder.
+ * Create an empty builder.
*/
public Builder() {
super();
}
/**
- * Create Builder with an existing CameraPosition data.
+ * Create a builder with an existing CameraPosition data.
*
* @param previous Existing CameraPosition values to use
*/
@@ -188,7 +189,7 @@ public final class CameraPosition implements Parcelable {
}
/**
- * Create Builder with an existing CameraPosition data.
+ * Create a builder with an existing CameraPosition data.
*
* @param typedArray TypedArray containing attribute values
*/
@@ -205,7 +206,7 @@ public final class CameraPosition implements Parcelable {
}
/**
- * Create Builder from an existing CameraPositionUpdate update.
+ * Create a builder from an existing CameraPositionUpdate update.
*
* @param update Update containing camera options
*/
@@ -220,7 +221,7 @@ public final class CameraPosition implements Parcelable {
}
/**
- * Create Builder from an existing CameraPositionUpdate update.
+ * Create builder from an existing CameraPositionUpdate update.
*
* @param update Update containing camera options
*/
@@ -235,7 +236,7 @@ public final class CameraPosition implements Parcelable {
* Sets the direction that the camera is pointing in, in degrees clockwise from north.
*
* @param bearing Bearing
- * @return Builder
+ * @return this
*/
public Builder bearing(double bearing) {
double direction = bearing;
@@ -252,19 +253,10 @@ public final class CameraPosition implements Parcelable {
}
/**
- * Builds a CameraPosition.
+ * Sets the location where the camera is pointing at.
*
- * @return CameraPosition
- */
- public CameraPosition build() {
- return new CameraPosition(target, zoom, tilt, bearing);
- }
-
- /**
- * Sets the location that the camera is pointing at.
- *
- * @param location Location
- * @return Builder
+ * @param location target of the camera
+ * @return this
*/
public Builder target(LatLng location) {
this.target = location;
@@ -272,28 +264,42 @@ public final class CameraPosition implements Parcelable {
}
/**
- * Set the tilt in degrees
+ * Set the tilt of the camera in degrees
* <p>
- * value is clamped to 0 and 60.
+ * value is clamped to {@link MapboxConstants#MINIMUM_TILT} and {@link MapboxConstants#MAXIMUM_TILT}.
* </p>
*
- * @param tilt Tilt value
- * @return Builder
+ * @param tilt Tilt value of the camera
+ * @return this
*/
- public Builder tilt(double tilt) {
+ public Builder tilt(@FloatRange(from = MapboxConstants.MINIMUM_TILT,
+ to = MapboxConstants.MAXIMUM_TILT) double tilt) {
this.tilt = MathUtils.clamp(tilt, MapboxConstants.MINIMUM_TILT, MapboxConstants.MAXIMUM_TILT);
return this;
}
/**
- * Set the zoom
+ * Set the zoom of the camera
+ * <p>
+ * Zoom ranges from {@link MapboxConstants#MINIMUM_ZOOM} to {@link MapboxConstants#MAXIMUM_ZOOM}
+ * </p>
*
- * @param zoom Zoom value
- * @return Builder
+ * @param zoom Zoom value of the camera
+ * @return this
*/
- public Builder zoom(double zoom) {
+ public Builder zoom(@FloatRange(from = MapboxConstants.MINIMUM_ZOOM,
+ to = MapboxConstants.MAXIMUM_ZOOM) double zoom) {
this.zoom = zoom;
return this;
}
+
+ /**
+ * Builds the CameraPosition.
+ *
+ * @return CameraPosition
+ */
+ public CameraPosition build() {
+ return new CameraPosition(target, zoom, tilt, bearing);
+ }
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdate.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdate.java
index 7e0dbf08fb..31f13cbcff 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdate.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdate.java
@@ -1,14 +1,22 @@
package com.mapbox.mapboxsdk.camera;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import com.mapbox.mapboxsdk.maps.MapboxMap;
/**
- * Interface definition for camera position changes.
+ * Interface definition for camera updates.
*/
public interface CameraUpdate {
+ /**
+ * Get the camera position from the camera update.
+ *
+ * @param mapboxMap Map object to build the position from
+ * @return the camera position from the implementing camera update
+ */
+ @Nullable
CameraPosition getCameraPosition(@NonNull MapboxMap mapboxMap);
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java
index 8e1411e273..50e33f4f9f 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java
@@ -42,7 +42,7 @@ public final class CameraUpdateFactory {
}
/**
- * Returns a {@link CameraUpdate} that transforms the camera such that the specified
+ * Returns a CameraUpdate that transforms the camera such that the specified
* latitude/longitude bounds are centered on screen at the greatest possible zoom level.
* You can specify padding, in order to inset the bounding box from the map view's edges.
* The returned CameraUpdate has a bearing of 0 and a tilt of 0.
@@ -56,7 +56,7 @@ public final class CameraUpdateFactory {
}
/**
- * Returns a {@link CameraUpdate} that transforms the camera such that the specified
+ * Returns a CameraUpdate that transforms the camera such that the specified
* latitude/longitude bounds are centered on screen at the greatest possible zoom level.
* You can specify padding, in order to inset the bounding box from the map view's edges.
* The returned CameraUpdate has a bearing of 0 and a tilt of 0.
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/GeometryConstants.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/GeometryConstants.java
new file mode 100644
index 0000000000..1a7544d33a
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/GeometryConstants.java
@@ -0,0 +1,63 @@
+package com.mapbox.mapboxsdk.constants;
+
+/**
+ * Contains constants used throughout the sdk classes.
+ *
+ * @since 6.0.0
+ */
+public class GeometryConstants {
+
+ /**
+ * The <a href='http://en.wikipedia.org/wiki/Earth_radius#Equatorial_radius'>equatorial radius</a>
+ * value in meters
+ *
+ * @since 6.0.0
+ */
+ public static final int RADIUS_EARTH_METERS = 6378137;
+
+ /**
+ * This constant represents the lowest longitude value available to represent a geolocation.
+ *
+ * @since 6.0.0
+ */
+ public static final double MIN_LONGITUDE = -180;
+
+ /**
+ * This constant represents the highest longitude value available to represent a geolocation.
+ *
+ * @since 6.0.0
+ */
+ public static final double MAX_LONGITUDE = 180;
+
+ /**
+ * This constant represents the lowest latitude value available to represent a geolocation.
+ *
+ * @since 6.0.0
+ */
+ public static final double MIN_LATITUDE = -90;
+
+ /**
+ * This constant represents the highest latitude value available to represent a geolocation.
+ *
+ * @since 6.0.0
+ */
+ public static final double MAX_LATITUDE = 90;
+
+ /**
+ * Maximum latitude value in Mercator projection.
+ *
+ * @since 6.0.0
+ */
+ public static final double MAX_MERCATOR_LATITUDE = 85.05112877980659;
+
+ /**
+ * Minimum latitude value in Mercator projection.
+ *
+ * @since 6.0.0
+ */
+ public static final double MIN_MERCATOR_LATITUDE = -85.05112877980659;
+
+ private GeometryConstants() {
+ // Private constructor to prevent initializing of this class.
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java
index ecb6ffe24e..3b35df4f4b 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java
@@ -55,7 +55,7 @@ public class MapboxConstants {
/**
* The currently supported maximum zoom level.
*/
- public static final float MAXIMUM_ZOOM = 20.0f;
+ public static final float MAXIMUM_ZOOM = 25.5f;
/**
* The currently supported maximum tilt value.
@@ -80,12 +80,12 @@ public class MapboxConstants {
/**
* The currently used minimun scale factor to clamp to when a quick zoom gesture occurs
*/
- public static final float MINIMUM_SCALE_FACTOR_CLAMP = 0.65f;
+ public static final float MINIMUM_SCALE_FACTOR_CLAMP = 0.00f;
/**
* The currently used maximum scale factor to clamp to when a quick zoom gesture occurs
*/
- public static final float MAXIMUM_SCALE_FACTOR_CLAMP = 1.35f;
+ public static final float MAXIMUM_SCALE_FACTOR_CLAMP = 0.45f;
/**
* Fragment Argument Key for MapboxMapOptions
@@ -133,5 +133,17 @@ public class MapboxConstants {
public static final String STATE_ATTRIBUTION_MARGIN_RIGHT = "mapbox_attrMarginRight";
public static final String STATE_ATTRIBUTION_MARGIN_BOTTOM = "mapbox_atrrMarginBottom";
public static final String STATE_ATTRIBUTION_ENABLED = "mapbox_atrrEnabled";
-
+ public static final String STATE_LOCATION_CHANGE_ANIMATION_ENABLED = "mapbox_locationChangeAnimationEnabled";
+ public static final String STATE_USING_CUSTOM_LOCATION_SOURCE = "mapbox_usingCustomLocationSource";
+ public static final String STATE_LOCATION_VIEW_ENABLED = "mapbox_locViewEnabled";
+ public static final String STATE_LOCATION_VIEW_FOREGROUND_DRAWABLE = "mapbox_locViewForegroundDrawable";
+ public static final String STATE_LOCATION_VIEW_FOREGROUND_BEARING_DRAWABLE = "mapbox_locViewBearingDrawable";
+ public static final String STATE_LOCATION_VIEW_FOREGROUND_TINT_COLOR = "mapbox_locViewForegroundTintColor";
+ public static final String STATE_LOCATION_VIEW_BACKGROUND_DRAWABLE = "mapbox_locViewBackgroundDrawable";
+ public static final String STATE_LOCATION_VIEW_BACKGROUND_OFFSET = "mapbox_locViewBackgroundOffset";
+ public static final String STATE_LOCATION_VIEW_BACKGROUND_TINT_COLOR = "mapbox_locViewBackgroundTintColor";
+ public static final String STATE_LOCATION_VIEW_ACCURACY_ALPHA = "mapbox_locViewAccuracyAlpha";
+ public static final String STATE_LOCATION_VIEW_ACCURACY_TINT_COLOR = "mapbox_locViewAccuracyTintColor";
+ public static final String STATE_LOCATION_VIEW_ACCURACY_THRESHOLD = "mapbox_locViewAccuracyThreshold";
+ public static final String STATE_LOCATION_VIEW_PADDING = "mapbox_locViewPadding";
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java
index 88c3bef673..ceac862f39 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java
@@ -2,23 +2,27 @@ package com.mapbox.mapboxsdk.constants;
import android.support.annotation.IntDef;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationView;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
- * MyBearingTracking exposes different types bearing tracking modes.
+ * MyBearingTracking exposes different types of bearing tracking modes.
+ * <p>
+ * These modes visualise the user direction by extracting the direction from either sensor or location data.
+ * </p>
+ * <p>
+ * Required to enable showing the user location first through {@link MapboxMap#setMyLocationEnabled(boolean)}.
+ * </p>
*
* @see com.mapbox.mapboxsdk.maps.TrackingSettings#setMyBearingTrackingMode(int)
* @see MyLocationView#setMyBearingTrackingMode(int)
*/
public class MyBearingTracking {
- /**
- * Indicates that the parameter accepts one of the values from MyBearingTracking.
- */
- @IntDef( {NONE, COMPASS, GPS, /**COMBINED**/})
+ @IntDef( {NONE, COMPASS, GPS})
@Retention(RetentionPolicy.SOURCE)
public @interface Mode {
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java
index a1744d701f..1283283fa5 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java
@@ -3,29 +3,34 @@ package com.mapbox.mapboxsdk.constants;
import android.support.annotation.IntDef;
import com.mapbox.mapboxsdk.maps.MapView;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.maps.TrackingSettings;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationView;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
- * MyLocationTracking exposes different types of locational tracking modes.
+ * MyLocationTracking exposes types of location tracking modes.
+ * * <p>
+ * This allows tracking the user location on screen by updating the camera position when a location update occurs.
+ * </p>
+ * <p>
+ * Required to enable showing the user location first through {@link MapboxMap#setMyLocationEnabled(boolean)}.
+ * </p>
*
- * @see com.mapbox.mapboxsdk.maps.TrackingSettings#setMyLocationTrackingMode(int)
- * @see MyLocationView#setMyLocationTrackingMode(int)
+ * @see MapboxMap#setMyLocationEnabled(boolean)
+ * @see TrackingSettings#setMyLocationTrackingMode(int)
*/
public class MyLocationTracking {
- /**
- * Indicates the parameter accepts one of the values from MyLocationTracking.
- */
@IntDef( {TRACKING_NONE, TRACKING_FOLLOW})
@Retention(RetentionPolicy.SOURCE)
public @interface Mode {
}
/**
- * Location tracking is disabled.
+ * Tracking the location of the user is disabled.
*/
public static final int TRACKING_NONE = 0x00000000;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/Style.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/Style.java
index 31e6313509..9943a72e06 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/Style.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/Style.java
@@ -17,7 +17,6 @@ import java.lang.annotation.RetentionPolicy;
*/
public class Style {
-
/**
* Indicates the parameter accepts one of the values from Style. Using one of these
* constants means your map style will always use the latest version and may change as we
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/IconBitmapChangedException.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/IconBitmapChangedException.java
index 7154049bd7..1f6b0efc4d 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/IconBitmapChangedException.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/IconBitmapChangedException.java
@@ -1,15 +1,13 @@
package com.mapbox.mapboxsdk.exceptions;
-import android.graphics.Bitmap;
-
import com.mapbox.mapboxsdk.annotations.Icon;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.maps.MapView;
/**
* <p>
- * A {@code IconBitmapChangedException} is thrown by {@link MapView} when a {@link Marker} is added
- * that has a {@link Icon} with a {@link Bitmap} that has been modified since the creation of the Icon.
+ * An IconBitmapChangedException is thrown by MapView when a Marker is added
+ * that has an Icon with a Bitmap that has been modified since the creation of the Icon.
* </p>
* You cannot modify a {@code Icon} after it has been added to the map in a {@code Marker}
*
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidLatLngBoundsException.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidLatLngBoundsException.java
index 08a23a7373..c1d0385815 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidLatLngBoundsException.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidLatLngBoundsException.java
@@ -1,8 +1,8 @@
package com.mapbox.mapboxsdk.exceptions;
/**
- * A InvalidLatLngBoundsException is thrown by {@link com.mapbox.mapboxsdk.geometry.LatLngBounds}
- * when there aren't enough {@link com.mapbox.mapboxsdk.geometry.LatLng} to create a bounds.
+ * An InvalidLatLngBoundsException is thrown by LatLngBounds
+ * when there aren't enough LatLng to create a bounds.
*/
public class InvalidLatLngBoundsException extends RuntimeException {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidMarkerPositionException.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidMarkerPositionException.java
index f0f9b9236b..44ee83265d 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidMarkerPositionException.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidMarkerPositionException.java
@@ -5,6 +5,9 @@ package com.mapbox.mapboxsdk.exceptions;
*/
public class InvalidMarkerPositionException extends RuntimeException {
+ /**
+ * Creates a invalid marker position exception thrown when a Marker object is created with an invalid LatLng position.
+ */
public InvalidMarkerPositionException() {
super("Adding an invalid Marker to a Map. "
+ "Missing the required position field. "
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxConfigurationException.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxConfigurationException.java
index 74bceb196c..e9a0261d85 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxConfigurationException.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxConfigurationException.java
@@ -8,10 +8,14 @@ import android.content.Context;
* This occurs either when {@link com.mapbox.mapboxsdk.Mapbox} is not correctly initialised or the provided access token
* through {@link com.mapbox.mapboxsdk.Mapbox#getInstance(Context, String)} isn't valid.
* </p>
+ *
* @see com.mapbox.mapboxsdk.Mapbox#getInstance(Context, String)
*/
public class MapboxConfigurationException extends RuntimeException {
+ /**
+ * Creates a Mapbox configuration exception thrown by MapboxMap when the SDK hasn't been properly initialised.
+ */
public MapboxConfigurationException() {
super("\nUsing MapView requires setting a valid access token. Use Mapbox.getInstance(Context context, "
+ "String accessToken) to provide one. "
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/TooManyIconsException.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/TooManyIconsException.java
index 8923d822f2..bffc10dc04 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/TooManyIconsException.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/TooManyIconsException.java
@@ -1,12 +1,11 @@
package com.mapbox.mapboxsdk.exceptions;
-import com.mapbox.mapboxsdk.annotations.Icon;
import com.mapbox.mapboxsdk.annotations.IconFactory;
/**
* <p>
- * A {@code TooManyIconsException} is thrown by {@link IconFactory} when it
- * cannot create a {@link Icon} because there are already too many icons created.
+ * A TooManyIconsException is thrown by IconFactory when it
+ * cannot create a Icon because there are already too many icons created.
* </p>
* You should try to reuse Icon objects whenever possible.
*
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ILatLng.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ILatLng.java
index 1af8e7cfc7..07df87af3a 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ILatLng.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ILatLng.java
@@ -1,12 +1,28 @@
package com.mapbox.mapboxsdk.geometry;
/**
- * Describes a latitude, longitude point.
+ * Describes a latitude, longitude, and altitude tuple.
*/
public interface ILatLng {
+
+ /**
+ * Get the latitude, in degrees.
+ *
+ * @return the latitude value in degrees
+ */
double getLatitude();
+ /**
+ * Get the longitude, in degrees.
+ *
+ * @return the longitude value in degrees
+ */
double getLongitude();
+ /**
+ * Get the altitude, in meters.
+ *
+ * @return the altitude value in meters
+ */
double getAltitude();
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/IProjectedMeters.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/IProjectedMeters.java
index 694c935143..db459d7cbb 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/IProjectedMeters.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/IProjectedMeters.java
@@ -4,7 +4,19 @@ package com.mapbox.mapboxsdk.geometry;
* Describes a projection in Mercator meters.
*/
public interface IProjectedMeters {
+
+ /**
+ * Get the north projection, in meters.
+ *
+ * @return the projected meters in north direction
+ */
double getNorthing();
+ /**
+ * Get the east projection, in meters.
+ *
+ * @return the projected meters in east direction
+ */
double getEasting();
+
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java
index ca2d3673b2..79023e2fd9 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java
@@ -3,9 +3,10 @@ package com.mapbox.mapboxsdk.geometry;
import android.location.Location;
import android.os.Parcel;
import android.os.Parcelable;
+import android.support.annotation.FloatRange;
+
+import com.mapbox.mapboxsdk.constants.GeometryConstants;
-import com.mapbox.services.android.telemetry.constants.GeoConstants;
-import com.mapbox.services.android.telemetry.utils.MathUtils;
/**
* A geographical location which contains a single latitude, longitude pair, with
@@ -21,6 +22,9 @@ import com.mapbox.services.android.telemetry.utils.MathUtils;
*/
public class LatLng implements ILatLng, Parcelable {
+ /**
+ * Inner class responsible for recreating Parcels into objects.
+ */
public static final Parcelable.Creator<LatLng> CREATOR = new Parcelable.Creator<LatLng>() {
public LatLng createFromParcel(Parcel in) {
return new LatLng(in);
@@ -44,7 +48,7 @@ public class LatLng implements ILatLng, Parcelable {
}
/**
- * Construct a new latitude, longitude point given float arguments
+ * Construct a new latitude, longitude point given double arguments
*
* @param latitude Latitude in degrees
* @param longitude Longitude in degrees
@@ -55,7 +59,7 @@ public class LatLng implements ILatLng, Parcelable {
}
/**
- * Construct a new latitude, longitude, altitude point given float arguments
+ * Construct a new latitude, longitude, altitude point given double arguments
*
* @param latitude Latitude in degrees
* @param longitude Longitude in degress
@@ -68,7 +72,7 @@ public class LatLng implements ILatLng, Parcelable {
}
/**
- * Transform a Location into a LatLng point
+ * Construct a new latitude, longitude, altitude point given location argument
*
* @param location Android Location
*/
@@ -77,38 +81,78 @@ public class LatLng implements ILatLng, Parcelable {
}
/**
- * Clone an existing latitude longitude point
+ * Construct a new latitude, longitude, altitude point given another latitude, longitude, altitude point.
*
- * @param aLatLng LatLng
+ * @param latLng LatLng to be cloned.
*/
- public LatLng(LatLng aLatLng) {
- this.latitude = aLatLng.latitude;
- this.longitude = aLatLng.longitude;
- this.altitude = aLatLng.altitude;
+ public LatLng(LatLng latLng) {
+ this.latitude = latLng.latitude;
+ this.longitude = latLng.longitude;
+ this.altitude = latLng.altitude;
}
+ /**
+ * Constructs a new latitude, longitude, altitude tuple given a parcel.
+ *
+ * @param in the parcel containing the latitude, longitude, altitude values
+ */
protected LatLng(Parcel in) {
setLatitude(in.readDouble());
setLongitude(in.readDouble());
setAltitude(in.readDouble());
}
- public void setLatitude(double latitude) {
+ /**
+ * Set the latitude, in degrees.
+ * <p>
+ * This value is in the range of [-90, 90], see {@link GeometryConstants#MIN_LATITUDE} and
+ * {@link GeometryConstants#MAX_LATITUDE}
+ * </p>
+ *
+ * @param latitude the latitude value in degrees
+ * @see GeometryConstants#MIN_LATITUDE
+ * @see GeometryConstants#MAX_LATITUDE
+ */
+ public void setLatitude(
+ @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) double latitude) {
if (Double.isNaN(latitude)) {
throw new IllegalArgumentException("latitude must not be NaN");
}
- if (Math.abs(latitude) > 90.0) {
+ if (Math.abs(latitude) > GeometryConstants.MAX_LATITUDE) {
throw new IllegalArgumentException("latitude must be between -90 and 90");
}
this.latitude = latitude;
}
+ /**
+ * Get the latitude, in degrees.
+ * <p>
+ * This value is in the range of [-90, 90], see {@link GeometryConstants#MIN_LATITUDE} and
+ * {@link GeometryConstants#MAX_LATITUDE}
+ * </p>
+ *
+ * @return the latitude value in degrees
+ * @see GeometryConstants#MIN_LATITUDE
+ * @see GeometryConstants#MAX_LATITUDE
+ */
@Override
public double getLatitude() {
return latitude;
}
- public void setLongitude(double longitude) {
+ /**
+ * Set the longitude, in degrees.
+ * <p>
+ * This value is in the range of [-180, 180], see {@link GeometryConstants#MIN_LONGITUDE} and
+ * {@link GeometryConstants#MAX_LONGITUDE}
+ * </p>
+ *
+ * @param longitude the longitude value in degrees
+ * @see GeometryConstants#MIN_LONGITUDE
+ * @see GeometryConstants#MAX_LONGITUDE
+ */
+ public void setLongitude(@FloatRange(from = GeometryConstants.MIN_LONGITUDE, to = GeometryConstants.MAX_LONGITUDE)
+ double longitude) {
if (Double.isNaN(longitude)) {
throw new IllegalArgumentException("longitude must not be NaN");
}
@@ -118,15 +162,36 @@ public class LatLng implements ILatLng, Parcelable {
this.longitude = longitude;
}
+ /**
+ * Get the longitude, in degrees.
+ * <p>
+ * This value is in the range of [-180, 180], see {@link GeometryConstants#MIN_LONGITUDE} and
+ * {@link GeometryConstants#MAX_LONGITUDE}
+ * </p>
+ *
+ * @return the longitude value in degrees
+ * @see GeometryConstants#MIN_LONGITUDE
+ * @see GeometryConstants#MAX_LONGITUDE
+ */
@Override
public double getLongitude() {
return longitude;
}
+ /**
+ * Set the altitude, in meters.
+ *
+ * @param altitude the altitude in meters
+ */
public void setAltitude(double altitude) {
this.altitude = altitude;
}
+ /**
+ * Get the altitude, in meters.
+ *
+ * @return the altitude value in meters
+ */
@Override
public double getAltitude() {
return altitude;
@@ -136,13 +201,44 @@ public class LatLng implements ILatLng, Parcelable {
* Return a new LatLng object with a wrapped Longitude. This allows original data object
* to remain unchanged.
*
- * @return New LatLng object with wrapped Longitude
+ * @return new LatLng object with wrapped Longitude
*/
public LatLng wrap() {
- longitude = MathUtils.wrap(longitude, GeoConstants.MIN_LONGITUDE, GeoConstants.MAX_LONGITUDE);
- return this;
+ return new LatLng(latitude, wrap(longitude, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE));
}
+
+ /**
+ * Constrains value to the given range (including min & max) via modular arithmetic.
+ * <p>
+ * Same formula as used in Core GL (wrap.hpp)
+ * std::fmod((std::fmod((value - min), d) + d), d) + min;
+ *
+ * Multiples of max value will be wrapped to max.
+ *
+ * @param value Value to wrap
+ * @param min Minimum value
+ * @param max Maximum value
+ * @return Wrapped value
+ */
+ static double wrap(double value, double min, double max) {
+ double delta = max - min;
+
+ double firstMod = (value - min) % delta;
+ double secondMod = (firstMod + delta) % delta;
+
+ if (value >= max && secondMod == 0) {
+ return max;
+ }
+ return secondMod + min;
+ }
+
+ /**
+ * Indicates whether some other object is "equal to" this one.
+ *
+ * @param object The object to compare
+ * @return True if equal, false if not
+ */
@Override
public boolean equals(Object object) {
if (this == object) {
@@ -158,6 +254,11 @@ public class LatLng implements ILatLng, Parcelable {
&& Double.compare(latLng.longitude, longitude) == 0;
}
+ /**
+ * Returns a hash code value for the object.
+ *
+ * @return the hash code value
+ */
@Override
public int hashCode() {
int result;
@@ -171,16 +272,32 @@ public class LatLng implements ILatLng, Parcelable {
return result;
}
+ /**
+ * Returns a string representation of the object.
+ *
+ * @return the string representation
+ */
@Override
public String toString() {
return "LatLng [latitude=" + latitude + ", longitude=" + longitude + ", altitude=" + altitude + "]";
}
+ /**
+ * Describe the kinds of special objects contained in this Parcelable instance's marshaled representation.
+ *
+ * @return a bitmask indicating the set of special object types marshaled by this Parcelable object instance.
+ */
@Override
public int describeContents() {
return 0;
}
+ /**
+ * Flatten this object in to a Parcel.
+ *
+ * @param out The Parcel in which the object should be written.
+ * @param flags Additional flags about how the object should be written
+ */
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeDouble(latitude);
@@ -213,6 +330,6 @@ public class LatLng implements ILatLng, Parcelable {
final double t3 = Math.sin(a1) * Math.sin(b1);
final double tt = Math.acos(t1 + t2 + t3);
- return GeoConstants.RADIUS_EARTH_METERS * tt;
+ return GeometryConstants.RADIUS_EARTH_METERS * tt;
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java
index 4a4e2a30aa..6d027a0cef 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java
@@ -3,9 +3,10 @@ package com.mapbox.mapboxsdk.geometry;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import com.mapbox.mapboxsdk.constants.GeometryConstants;
import com.mapbox.mapboxsdk.exceptions.InvalidLatLngBoundsException;
-import com.mapbox.services.android.telemetry.constants.GeoConstants;
import java.util.ArrayList;
import java.util.List;
@@ -18,10 +19,10 @@ import java.util.List;
*/
public class LatLngBounds implements Parcelable {
- private final double mLatNorth;
- private final double mLatSouth;
- private final double mLonEast;
- private final double mLonWest;
+ private final double latitudeNorth;
+ private final double latitudeSouth;
+ private final double longitudeEast;
+ private final double longitudeWest;
/**
* Construct a new LatLngBounds based on its corners, given in NESW
@@ -34,10 +35,10 @@ public class LatLngBounds implements Parcelable {
*/
LatLngBounds(final double northLatitude, final double eastLongitude, final double southLatitude,
final double westLongitude) {
- this.mLatNorth = northLatitude;
- this.mLonEast = eastLongitude;
- this.mLatSouth = southLatitude;
- this.mLonWest = westLongitude;
+ this.latitudeNorth = northLatitude;
+ this.longitudeEast = eastLongitude;
+ this.latitudeSouth = southLatitude;
+ this.longitudeWest = westLongitude;
}
/**
@@ -47,8 +48,8 @@ public class LatLngBounds implements Parcelable {
*/
public static LatLngBounds world() {
return new LatLngBounds.Builder()
- .include(new LatLng(GeoConstants.MAX_LATITUDE, GeoConstants.MAX_LONGITUDE))
- .include(new LatLng(GeoConstants.MIN_LATITUDE, GeoConstants.MIN_LONGITUDE))
+ .include(new LatLng(GeometryConstants.MAX_LATITUDE, GeometryConstants.MAX_LONGITUDE))
+ .include(new LatLng(GeometryConstants.MIN_LATITUDE, GeometryConstants.MIN_LONGITUDE))
.build();
}
@@ -59,8 +60,8 @@ public class LatLngBounds implements Parcelable {
* @return LatLng center of this LatLngBounds
*/
public LatLng getCenter() {
- return new LatLng((this.mLatNorth + this.mLatSouth) / 2,
- (this.mLonEast + this.mLonWest) / 2);
+ return new LatLng((this.latitudeNorth + this.latitudeSouth) / 2,
+ (this.longitudeEast + this.longitudeWest) / 2);
}
/**
@@ -69,7 +70,7 @@ public class LatLngBounds implements Parcelable {
* @return double latitude value for north
*/
public double getLatNorth() {
- return this.mLatNorth;
+ return this.latitudeNorth;
}
/**
@@ -78,7 +79,7 @@ public class LatLngBounds implements Parcelable {
* @return double latitude value for south
*/
public double getLatSouth() {
- return this.mLatSouth;
+ return this.latitudeSouth;
}
/**
@@ -87,7 +88,7 @@ public class LatLngBounds implements Parcelable {
* @return double longitude value for east
*/
public double getLonEast() {
- return this.mLonEast;
+ return this.longitudeEast;
}
/**
@@ -96,7 +97,7 @@ public class LatLngBounds implements Parcelable {
* @return double longitude value for west
*/
public double getLonWest() {
- return this.mLonWest;
+ return this.longitudeWest;
}
/**
@@ -105,7 +106,7 @@ public class LatLngBounds implements Parcelable {
* @return LatLng of the south west corner
*/
public LatLng getSouthWest() {
- return new LatLng(mLatSouth, mLonWest);
+ return new LatLng(latitudeSouth, longitudeWest);
}
/**
@@ -114,7 +115,7 @@ public class LatLngBounds implements Parcelable {
* @return LatLng of the north east corner
*/
public LatLng getNorthEast() {
- return new LatLng(mLatNorth, mLonEast);
+ return new LatLng(latitudeNorth, longitudeEast);
}
/**
@@ -123,7 +124,7 @@ public class LatLngBounds implements Parcelable {
* @return LatLng of the south east corner
*/
public LatLng getSouthEast() {
- return new LatLng(mLatSouth, mLonEast);
+ return new LatLng(latitudeSouth, longitudeEast);
}
/**
@@ -132,7 +133,7 @@ public class LatLngBounds implements Parcelable {
* @return LatLng of the north west corner
*/
public LatLng getNorthWest() {
- return new LatLng(mLatNorth, mLonWest);
+ return new LatLng(latitudeNorth, longitudeWest);
}
/**
@@ -151,7 +152,7 @@ public class LatLngBounds implements Parcelable {
* @return Span distance
*/
public double getLatitudeSpan() {
- return Math.abs(this.mLatNorth - this.mLatSouth);
+ return Math.abs(this.latitudeNorth - this.latitudeSouth);
}
/**
@@ -161,7 +162,7 @@ public class LatLngBounds implements Parcelable {
* @return Span distance
*/
public double getLongitudeSpan() {
- return Math.abs(this.mLonEast - this.mLonWest);
+ return Math.abs(this.longitudeEast - this.longitudeWest);
}
@@ -174,9 +175,15 @@ public class LatLngBounds implements Parcelable {
return getLongitudeSpan() == 0.0 || getLatitudeSpan() == 0.0;
}
+ /**
+ * Returns a string representaton of the object.
+ *
+ * @return the string representation
+ */
@Override
public String toString() {
- return "N:" + this.mLatNorth + "; E:" + this.mLonEast + "; S:" + this.mLatSouth + "; W:" + this.mLonWest;
+ return "N:" + this.latitudeNorth + "; E:" + this.longitudeEast + "; S:" + this.latitudeSouth
+ + "; W:" + this.longitudeWest;
}
/**
@@ -187,10 +194,10 @@ public class LatLngBounds implements Parcelable {
* @return LatLngBounds
*/
static LatLngBounds fromLatLngs(final List<? extends ILatLng> latLngs) {
- double minLat = 90;
- double minLon = 180;
- double maxLat = -90;
- double maxLon = -180;
+ double minLat = GeometryConstants.MAX_LATITUDE;
+ double minLon = GeometryConstants.MAX_LONGITUDE;
+ double maxLat = GeometryConstants.MIN_LATITUDE;
+ double maxLon = GeometryConstants.MIN_LONGITUDE;
for (final ILatLng gp : latLngs) {
final double latitude = gp.getLatitude();
@@ -215,6 +222,40 @@ public class LatLngBounds implements Parcelable {
}
/**
+ * Constructs a LatLngBounds from doubles representing a LatLng pair.
+ * <p>
+ * This method doesn't recalculate most east or most west boundaries.
+ * </p>
+ */
+ public static LatLngBounds from(double latNorth, double lonEast, double latSouth, double lonWest) {
+ return new LatLngBounds(latNorth, lonEast, latSouth, lonWest);
+ }
+
+ private static double lat_(int z, int y) {
+ double n = Math.PI - 2.0 * Math.PI * y / Math.pow(2.0, z);
+ return Math.toDegrees(Math.atan(0.5 * (Math.exp(n) - Math.exp(-n))));
+ }
+
+ private static double lon_(int z, int x) {
+ return x / Math.pow(2.0, z) * 360.0 - GeometryConstants.MAX_LONGITUDE;
+ }
+
+ /**
+ * Constructs a LatLngBounds from a Tile identifier.
+ *
+ * Returned bounds will have latitude in the range of Mercator projection.
+ * @see GeometryConstants#MIN_MERCATOR_LATITUDE
+ * @see GeometryConstants#MAX_MERCATOR_LATITUDE
+ *
+ * @param z Tile zoom level.
+ * @param x Tile X coordinate.
+ * @param y Tile Y coordinate.
+ */
+ public static LatLngBounds from(int z, int x, int y) {
+ return new LatLngBounds(lat_(z, y), lon_(z, x + 1), lat_(z, y + 1), lon_(z, x));
+ }
+
+ /**
* Constructs a LatLngBounds from current bounds with an additional latitude-longitude pair.
*
* @param latLng the latitude lognitude pair to include in the bounds.
@@ -241,10 +282,10 @@ public class LatLngBounds implements Parcelable {
}
if (o instanceof LatLngBounds) {
LatLngBounds other = (LatLngBounds) o;
- return mLatNorth == other.getLatNorth()
- && mLatSouth == other.getLatSouth()
- && mLonEast == other.getLonEast()
- && mLonWest == other.getLonWest();
+ return latitudeNorth == other.getLatNorth()
+ && latitudeSouth == other.getLatSouth()
+ && longitudeEast == other.getLonEast()
+ && longitudeWest == other.getLonWest();
}
return false;
}
@@ -258,10 +299,10 @@ public class LatLngBounds implements Parcelable {
public boolean contains(final ILatLng latLng) {
final double latitude = latLng.getLatitude();
final double longitude = latLng.getLongitude();
- return ((latitude <= this.mLatNorth)
- && (latitude >= this.mLatSouth))
- && ((longitude <= this.mLonEast)
- && (longitude >= this.mLonWest));
+ return ((latitude <= this.latitudeNorth)
+ && (latitude >= this.latitudeSouth))
+ && ((longitude <= this.longitudeEast)
+ && (longitude >= this.longitudeWest));
}
/**
@@ -288,17 +329,17 @@ public class LatLngBounds implements Parcelable {
* Returns a new LatLngBounds that stretches to include another LatLngBounds,
* given by corner points.
*
- * @param lonNorth Northern Longitude
- * @param latEast Eastern Latitude
- * @param lonSouth Southern Longitude
- * @param latWest Western Longitude
+ * @param latNorth Northern Latitude
+ * @param lonEast Eastern Longitude
+ * @param latSouth Southern Latitude
+ * @param lonWest Western Longitude
* @return BoundingBox
*/
- public LatLngBounds union(final double lonNorth, final double latEast, final double lonSouth, final double latWest) {
- return new LatLngBounds((this.mLatNorth < lonNorth) ? lonNorth : this.mLatNorth,
- (this.mLonEast < latEast) ? latEast : this.mLonEast,
- (this.mLatSouth > lonSouth) ? lonSouth : this.mLatSouth,
- (this.mLonWest > latWest) ? latWest : this.mLonWest);
+ public LatLngBounds union(final double latNorth, final double lonEast, final double latSouth, final double lonWest) {
+ return new LatLngBounds((this.latitudeNorth < latNorth) ? latNorth : this.latitudeNorth,
+ (this.longitudeEast < lonEast) ? lonEast : this.longitudeEast,
+ (this.latitudeSouth > latSouth) ? latSouth : this.latitudeSouth,
+ (this.longitudeWest > lonWest) ? lonWest : this.longitudeWest);
}
/**
@@ -307,14 +348,15 @@ public class LatLngBounds implements Parcelable {
* @param box LatLngBounds to intersect with
* @return LatLngBounds
*/
+ @Nullable
public LatLngBounds intersect(LatLngBounds box) {
- double minLatWest = Math.max(getLonWest(), box.getLonWest());
- double maxLatEast = Math.min(getLonEast(), box.getLonEast());
- if (maxLatEast > minLatWest) {
- double minLonSouth = Math.max(getLatSouth(), box.getLatSouth());
- double maxLonNorth = Math.min(getLatNorth(), box.getLatNorth());
- if (maxLonNorth > minLonSouth) {
- return new LatLngBounds(maxLonNorth, maxLatEast, minLonSouth, minLatWest);
+ double minLonWest = Math.max(getLonWest(), box.getLonWest());
+ double maxLonEast = Math.min(getLonEast(), box.getLonEast());
+ if (maxLonEast > minLonWest) {
+ double minLatSouth = Math.max(getLatSouth(), box.getLatSouth());
+ double maxLatNorth = Math.min(getLatNorth(), box.getLatNorth());
+ if (maxLatNorth > minLatSouth) {
+ return new LatLngBounds(maxLatNorth, maxLonEast, minLatSouth, minLonWest);
}
}
return null;
@@ -334,6 +376,9 @@ public class LatLngBounds implements Parcelable {
return intersect(new LatLngBounds(northLatitude, eastLongitude, southLatitude, westLongitude));
}
+ /**
+ * Inner class responsible for recreating Parcels into objects.
+ */
public static final Parcelable.Creator<LatLngBounds> CREATOR =
new Parcelable.Creator<LatLngBounds>() {
@Override
@@ -347,25 +392,41 @@ public class LatLngBounds implements Parcelable {
}
};
+ /**
+ * Returns a hash code value for the object.
+ *
+ * @return the hash code
+ */
@Override
public int hashCode() {
- return (int) ((mLatNorth + 90)
- + ((mLatSouth + 90) * 1000)
- + ((mLonEast + 180) * 1000000)
- + ((mLonEast + 180) * 1000000000));
+ return (int) ((latitudeNorth + 90)
+ + ((latitudeSouth + 90) * 1000)
+ + ((longitudeEast + 180) * 1000000)
+ + ((longitudeEast + 180) * 1000000000));
}
+ /**
+ * Describe the kinds of special objects contained in this Parcelable instance's marshaled representation.
+ *
+ * @return a bitmask indicating the set of special object types marshaled by this Parcelable object instance.
+ */
@Override
public int describeContents() {
return 0;
}
+ /**
+ * Flatten this object in to a Parcel.
+ *
+ * @param out The Parcel in which the object should be written.
+ * @param flags Additional flags about how the object should be written
+ */
@Override
- public void writeToParcel(final Parcel out, final int arg1) {
- out.writeDouble(this.mLatNorth);
- out.writeDouble(this.mLonEast);
- out.writeDouble(this.mLatSouth);
- out.writeDouble(this.mLonWest);
+ public void writeToParcel(final Parcel out, final int flags) {
+ out.writeDouble(this.latitudeNorth);
+ out.writeDouble(this.longitudeEast);
+ out.writeDouble(this.latitudeSouth);
+ out.writeDouble(this.longitudeWest);
}
private static LatLngBounds readFromParcel(final Parcel in) {
@@ -381,28 +442,53 @@ public class LatLngBounds implements Parcelable {
*/
public static final class Builder {
- private List<LatLng> mLatLngList;
+ private List<LatLng> latLngList;
+ /**
+ * Constructs a builder to compose LatLng objects to a LatLngBounds.
+ */
public Builder() {
- mLatLngList = new ArrayList<>();
+ latLngList = new ArrayList<>();
}
+ /**
+ * Builds a new LatLngBounds.
+ * <p>
+ * Throws an {@link InvalidLatLngBoundsException} when no LatLngBounds can be created.
+ * </p>
+ *
+ * @return the build LatLngBounds
+ */
public LatLngBounds build() {
- if (mLatLngList.size() < 2) {
- throw new InvalidLatLngBoundsException(mLatLngList.size());
+ if (latLngList.size() < 2) {
+ throw new InvalidLatLngBoundsException(latLngList.size());
}
- return LatLngBounds.fromLatLngs(mLatLngList);
+ return LatLngBounds.fromLatLngs(latLngList);
}
+ /**
+ * Adds a LatLng object to the LatLngBounds.Builder.
+ *
+ * @param latLngs the List of LatLng objects to be added
+ * @return this
+ */
public Builder includes(List<LatLng> latLngs) {
for (LatLng point : latLngs) {
- mLatLngList.add(point);
+ include(point);
}
return this;
}
+ /**
+ * Adds a LatLng object to the LatLngBounds.Builder.
+ *
+ * @param latLng the LatLng to be added
+ * @return this
+ */
public Builder include(@NonNull LatLng latLng) {
- mLatLngList.add(latLng);
+ if (!latLngList.contains(latLng)) {
+ latLngList.add(latLng);
+ }
return this;
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngSpan.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngSpan.java
index d00ccdb9b8..322c7dfb74 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngSpan.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngSpan.java
@@ -64,19 +64,28 @@ public class LatLngSpan implements Parcelable {
mLongitudeSpan = longitudeSpan;
}
+ /**
+ * Indicates whether some other object is "equal to" this one.
+ *
+ * @param object The object to compare
+ * @return True if equal, false if not
+ */
@Override
- public boolean equals(Object o) {
- if (this == o) {
+ public boolean equals(Object object) {
+ if (this == object) {
return true;
}
- if (o instanceof LatLngSpan) {
- LatLngSpan other = (LatLngSpan) o;
+ if (object instanceof LatLngSpan) {
+ LatLngSpan other = (LatLngSpan) object;
return mLongitudeSpan == other.getLongitudeSpan()
&& mLatitudeSpan == other.getLatitudeSpan();
}
return false;
}
+ /**
+ * Inner class responsible for recreating Parcels into objects.
+ */
public static final Parcelable.Creator<LatLngSpan> CREATOR =
new Parcelable.Creator<LatLngSpan>() {
@Override
@@ -90,14 +99,41 @@ public class LatLngSpan implements Parcelable {
}
};
+ /**
+ * Describe the kinds of special objects contained in this Parcelable instance's marshaled representation.
+ *
+ * @return a bitmask indicating the set of special object types marshaled by this Parcelable object instance.
+ */
@Override
public int describeContents() {
return 0;
}
+ /**
+ * Flatten this object in to a Parcel.
+ *
+ * @param out Parcel in which the object should be written
+ * @param flags Additional flags about how the object should be written
+ */
@Override
- public void writeToParcel(Parcel out, int arg1) {
+ public void writeToParcel(Parcel out, int flags) {
out.writeDouble(mLatitudeSpan);
out.writeDouble(mLongitudeSpan);
}
+
+ /**
+ * Returns a hash code value for the object.
+ *
+ * @return hash code value of this
+ */
+ @Override
+ public int hashCode() {
+ int result;
+ long temp;
+ temp = Double.doubleToLongBits(mLatitudeSpan);
+ result = (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(mLongitudeSpan);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ return result;
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ProjectedMeters.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ProjectedMeters.java
index 761d8f2a8b..fa84c33b2b 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ProjectedMeters.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ProjectedMeters.java
@@ -13,6 +13,9 @@ import android.os.Parcelable;
*/
public class ProjectedMeters implements IProjectedMeters, Parcelable {
+ /**
+ * Inner class responsible for recreating Parcels into objects.
+ */
public static final Creator<ProjectedMeters> CREATOR = new Creator<ProjectedMeters>() {
public ProjectedMeters createFromParcel(Parcel in) {
return new ProjectedMeters(in);
@@ -47,6 +50,12 @@ public class ProjectedMeters implements IProjectedMeters, Parcelable {
this.easting = projectedMeters.easting;
}
+ /**
+ * Creates a ProjectedMeters from a Parcel.
+ *
+ * @param in The parcel to create from
+ * @return a bitmask indicating the set of special object types marshaled by this Parcelable object instance.
+ */
private ProjectedMeters(Parcel in) {
northing = in.readDouble();
easting = in.readDouble();
@@ -72,22 +81,32 @@ public class ProjectedMeters implements IProjectedMeters, Parcelable {
return easting;
}
+ /**
+ * Indicates whether some other object is "equal to" this one.
+ *
+ * @param other The object to compare this to
+ * @return true if equal, false if not
+ */
@Override
- public boolean equals(Object o) {
- if (this == o) {
+ public boolean equals(Object other) {
+ if (this == other) {
return true;
}
- if (o == null || getClass() != o.getClass()) {
+ if (other == null || getClass() != other.getClass()) {
return false;
}
- ProjectedMeters projectedMeters = (ProjectedMeters) o;
+ ProjectedMeters projectedMeters = (ProjectedMeters) other;
return Double.compare(projectedMeters.easting, easting) == 0
&& Double.compare(projectedMeters.northing, northing) == 0;
-
}
+ /**
+ * Returns a hash code value for the object.
+ *
+ * @return the hash code of this
+ */
@Override
public int hashCode() {
int result;
@@ -99,16 +118,32 @@ public class ProjectedMeters implements IProjectedMeters, Parcelable {
return result;
}
+ /**
+ * Returns a string representation of the object.
+ *
+ * @return the string representation of this
+ */
@Override
public String toString() {
return "ProjectedMeters [northing=" + northing + ", easting=" + easting + "]";
}
+ /**
+ * Describe the kinds of special objects contained in this Parcelable instance's marshaled representation.
+ *
+ * @return a bitmask indicating the set of special object types marshaled by this Parcelable object instance.
+ */
@Override
public int describeContents() {
return 0;
}
+ /**
+ * Flatten this object in to a Parcel.
+ *
+ * @param out The Parcel in which the object should be written.
+ * @param flags Additional flags about how the object should be written
+ */
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeDouble(northing);
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java
index c5b8ad3077..c09c00fced 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java
@@ -37,6 +37,11 @@ public class VisibleRegion implements Parcelable {
*/
public final LatLngBounds latLngBounds;
+ /**
+ * Creates a VisibleRegion from a Parcel.
+ *
+ * @param in The Parcel to create this from
+ */
private VisibleRegion(Parcel in) {
this.farLeft = in.readParcelable(LatLng.class.getClassLoader());
this.farRight = in.readParcelable(LatLng.class.getClassLoader());
@@ -46,7 +51,7 @@ public class VisibleRegion implements Parcelable {
}
/**
- * Creates a new VisibleRegion given the four corners of the camera.
+ * Creates a VisibleRegion given the four corners of the camera.
*
* @param farLeft A LatLng object containing the latitude and longitude of the near left corner of the region.
* @param farRight A LatLng object containing the latitude and longitude of the near left corner of the region.
@@ -88,12 +93,22 @@ public class VisibleRegion implements Parcelable {
&& latLngBounds.equals(visibleRegion.latLngBounds);
}
+ /**
+ * The string representation of the object.
+ *
+ * @return the string representation of this
+ */
@Override
public String toString() {
return "[farLeft [" + farLeft + "], farRight [" + farRight + "], nearLeft [" + nearLeft + "], nearRight ["
+ nearRight + "], latLngBounds [" + latLngBounds + "]]";
}
+ /**
+ * Returns a hash code value for the object.
+ *
+ * @return the hash code
+ */
@Override
public int hashCode() {
return ((farLeft.hashCode() + 90)
@@ -102,11 +117,22 @@ public class VisibleRegion implements Parcelable {
+ ((nearRight.hashCode() + 180) * 1000000000));
}
+ /**
+ * Describe the kinds of special objects contained in this Parcelable instance's marshaled representation.
+ *
+ * @return a bitmask indicating the set of special object types marshaled by this Parcelable object instance.
+ */
@Override
public int describeContents() {
return 0;
}
+ /**
+ * Flatten this object in to a Parcel.
+ *
+ * @param out The Parcel in which the object should be written.
+ * @param flags Additional flags about how the object should be written
+ */
@Override
public void writeToParcel(Parcel out, int flags) {
out.writeParcelable(farLeft, flags);
@@ -116,6 +142,9 @@ public class VisibleRegion implements Parcelable {
out.writeParcelable(latLngBounds, flags);
}
+ /**
+ * Inner class responsible for recreating Parcels into objects.
+ */
public static final Parcelable.Creator<VisibleRegion> CREATOR =
new Parcelable.Creator<VisibleRegion>() {
public VisibleRegion createFromParcel(Parcel in) {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java
index 9c8cda5544..32aa250997 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java
@@ -56,13 +56,14 @@ class HTTPRequest implements Callback {
mNativePtr = nativePtr;
try {
- // Don't try a request if we aren't connected
- if (!Mapbox.isConnected()) {
+ HttpUrl httpUrl = HttpUrl.parse(resourceUrl);
+ final String host = httpUrl.host().toLowerCase(MapboxConstants.MAPBOX_LOCALE);
+
+ // Don't try a request to remote server if we aren't connected
+ if (!Mapbox.isConnected() && !host.equals("127.0.0.1") && !host.equals("localhost")) {
throw new NoRouteToHostException("No Internet connection available.");
}
- HttpUrl httpUrl = HttpUrl.parse(resourceUrl);
- final String host = httpUrl.host().toLowerCase(MapboxConstants.MAPBOX_LOCALE);
if (host.equals("mapbox.com") || host.endsWith(".mapbox.com") || host.equals("mapbox.cn")
|| host.endsWith(".mapbox.cn")) {
if (httpUrl.querySize() == 0) {
@@ -84,7 +85,14 @@ class HTTPRequest implements Callback {
}
mRequest = builder.build();
mCall = mClient.newCall(mRequest);
- mCall.enqueue(this);
+
+ // TODO remove code block for workaround in #10303
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1) {
+ mCall.enqueue(this);
+ } else {
+ // Calling execute instead of enqueue is a workaround for #10303
+ onResponse(mCall, mCall.execute());
+ }
} catch (Exception exception) {
onFailure(exception);
}
@@ -109,13 +117,11 @@ class HTTPRequest implements Callback {
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
- Timber.v(String.format("[HTTP] Request was successful (code = %d).", response.code()));
+ Timber.v("[HTTP] Request was successful (code = %s).", response.code());
} else {
// We don't want to call this unsuccessful because a 304 isn't really an error
String message = !TextUtils.isEmpty(response.message()) ? response.message() : "No additional information";
- Timber.d(String.format(
- "[HTTP] Request with response code = %d: %s",
- response.code(), message));
+ Timber.d("[HTTP] Request with response code = %s: %s", response.code(), message);
}
byte[] body;
@@ -160,15 +166,12 @@ class HTTPRequest implements Callback {
String errorMessage = e.getMessage() != null ? e.getMessage() : "Error processing the request";
if (type == TEMPORARY_ERROR) {
- Timber.d(String.format(MapboxConstants.MAPBOX_LOCALE,
- "Request failed due to a temporary error: %s", errorMessage));
+ Timber.d("Request failed due to a temporary error: %s", errorMessage);
} else if (type == CONNECTION_ERROR) {
- Timber.i(String.format(MapboxConstants.MAPBOX_LOCALE,
- "Request failed due to a connection error: %s", errorMessage));
+ Timber.i("Request failed due to a connection error: %s", errorMessage);
} else {
// PERMANENT_ERROR
- Timber.w(String.format(MapboxConstants.MAPBOX_LOCALE,
- "Request failed due to a permanent error: %s", errorMessage));
+ Timber.w("Request failed due to a permanent error: %s", errorMessage);
}
mLock.lock();
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java
index 4e934fa3cc..c6bc13f538 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationSource.java
@@ -2,22 +2,19 @@ package com.mapbox.mapboxsdk.location;
import android.content.Context;
import android.location.Location;
-import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.services.android.telemetry.location.LocationEngine;
import com.mapbox.services.android.telemetry.location.LocationEngineListener;
import com.mapbox.services.android.telemetry.location.LocationEnginePriority;
-import com.mapbox.services.android.telemetry.permissions.PermissionsManager;
import com.mapzen.android.lost.api.LocationListener;
import com.mapzen.android.lost.api.LocationRequest;
import com.mapzen.android.lost.api.LocationServices;
import com.mapzen.android.lost.api.LostApiClient;
-import java.lang.ref.WeakReference;
-
-import timber.log.Timber;
-
/**
+ * LocationEngine using the Open Source Lost library
* Manages locational updates. Contains methods to register and unregister location listeners.
* <ul>
* <li>You can register a LocationEngineListener with LocationSource#addLocationEngineListener(LocationEngineListener)
@@ -31,35 +28,31 @@ import timber.log.Timber;
* overhead). Do not unregister in Activity.onSaveInstanceState(), because this won't be called if the user moves back
* in the history stack.
* </p>
+ *
+ * @deprecated Use a {@link Mapbox#getLocationEngine()} instead.
*/
-public class LocationSource extends LocationEngine implements
- LostApiClient.ConnectionCallbacks, LocationListener {
-
- private static LocationEngine instance;
+@Deprecated
+public class LocationSource extends LocationEngine implements LocationListener {
- private WeakReference<Context> context;
+ private Context context;
private LostApiClient lostApiClient;
- private LocationSource(Context context) {
+ /**
+ * Constructs a location source instance.
+ *
+ * @param context the context from which the Application context will be derived.
+ */
+ public LocationSource(Context context) {
super();
- this.context = new WeakReference<>(context);
- lostApiClient = new LostApiClient.Builder(this.context.get())
- .addConnectionCallbacks(this)
- .build();
+ this.context = context.getApplicationContext();
+ lostApiClient = new LostApiClient.Builder(this.context).build();
}
/**
- * Get the LocationEngine instance.
- *
- * @param context a Context from which the application context is derived
- * @return the LocationEngine instance
+ * Constructs a location source instance.
+ * Needed to create empty location source implementations.
*/
- public static synchronized LocationEngine getLocationEngine(@NonNull Context context) {
- if (instance == null) {
- instance = new LocationSource(context.getApplicationContext());
- }
-
- return instance;
+ public LocationSource() {
}
/**
@@ -68,9 +61,12 @@ public class LocationSource extends LocationEngine implements
*/
@Override
public void activate() {
- if (lostApiClient != null && !lostApiClient.isConnected()) {
+ if (!lostApiClient.isConnected()) {
lostApiClient.connect();
}
+ for (LocationEngineListener listener : locationListeners) {
+ listener.onConnected();
+ }
}
/**
@@ -80,7 +76,7 @@ public class LocationSource extends LocationEngine implements
*/
@Override
public void deactivate() {
- if (lostApiClient != null && lostApiClient.isConnected()) {
+ if (lostApiClient.isConnected()) {
lostApiClient.disconnect();
}
}
@@ -97,35 +93,17 @@ public class LocationSource extends LocationEngine implements
}
/**
- * Invoked when the location provider has connected.
- */
- @Override
- public void onConnected() {
- for (LocationEngineListener listener : locationListeners) {
- listener.onConnected();
- }
- }
-
- /**
- * Invoked when the location provider connection has been suspended.
- */
- @Override
- public void onConnectionSuspended() {
- Timber.d("Connection suspended.");
- }
-
- /**
* Returns the Last known location is the location provider is connected and location permissions are granted.
*
* @return the last known location
*/
@Override
+ @Nullable
public Location getLastLocation() {
- if (lostApiClient.isConnected() && PermissionsManager.areLocationPermissionsGranted(context.get())) {
+ if (lostApiClient.isConnected()) {
//noinspection MissingPermission
- return LocationServices.FusedLocationApi.getLastLocation(lostApiClient);
+ return LocationServices.FusedLocationApi.getLastLocation();
}
-
return null;
}
@@ -134,13 +112,18 @@ public class LocationSource extends LocationEngine implements
*/
@Override
public void requestLocationUpdates() {
- // Common params
- LocationRequest request = LocationRequest.create()
- .setInterval(1000)
- .setFastestInterval(1000)
- .setSmallestDisplacement(3.0f);
+ LocationRequest request = LocationRequest.create();
+
+ if (interval != null) {
+ request.setInterval(interval);
+ }
+ if (fastestInterval != null) {
+ request.setFastestInterval(fastestInterval);
+ }
+ if (smallestDisplacement != null) {
+ request.setSmallestDisplacement(smallestDisplacement);
+ }
- // Priority matching is straightforward
if (priority == LocationEnginePriority.NO_POWER) {
request.setPriority(LocationRequest.PRIORITY_NO_POWER);
} else if (priority == LocationEnginePriority.LOW_POWER) {
@@ -151,9 +134,9 @@ public class LocationSource extends LocationEngine implements
request.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
}
- if (lostApiClient.isConnected() && PermissionsManager.areLocationPermissionsGranted(context.get())) {
+ if (lostApiClient.isConnected()) {
//noinspection MissingPermission
- LocationServices.FusedLocationApi.requestLocationUpdates(lostApiClient, request, this);
+ LocationServices.FusedLocationApi.requestLocationUpdates(request, this);
}
}
@@ -163,11 +146,21 @@ public class LocationSource extends LocationEngine implements
@Override
public void removeLocationUpdates() {
if (lostApiClient.isConnected()) {
- LocationServices.FusedLocationApi.removeLocationUpdates(lostApiClient, this);
+ LocationServices.FusedLocationApi.removeLocationUpdates(this);
}
}
/**
+ * Returns the location engine type.
+ *
+ * @return Lost type
+ */
+ @Override
+ public Type obtainType() {
+ return Type.LOST;
+ }
+
+ /**
* Invoked when the Location has changed.
*
* @param location the new location
@@ -178,4 +171,4 @@ public class LocationSource extends LocationEngine implements
listener.onLocationChanged(location);
}
}
-}
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/package-info.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/package-info.java
index 6b0c9a76c0..b27559e95e 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/package-info.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/package-info.java
@@ -1,4 +1,4 @@
/**
* Contains the Mapbox Maps Android Location API classes.
*/
-package com.mapbox.mapboxsdk.location;
+package com.mapbox.mapboxsdk.location; \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java
index 7e7947047e..9f256c341b 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java
@@ -1,11 +1,16 @@
package com.mapbox.mapboxsdk.maps;
+import android.graphics.Bitmap;
import android.graphics.PointF;
+import android.graphics.Rect;
import android.graphics.RectF;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.util.LongSparseArray;
+import android.view.View;
+import com.mapbox.mapboxsdk.Mapbox;
+import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.annotations.Annotation;
import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions;
import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions;
@@ -18,9 +23,10 @@ import com.mapbox.mapboxsdk.annotations.Polyline;
import com.mapbox.mapboxsdk.annotations.PolylineOptions;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
+import timber.log.Timber;
+
/**
* Responsible for managing and tracking state of Annotations linked to Map. All events related to
* annotations that occur on {@link MapboxMap} are forwarded to this class.
@@ -34,7 +40,8 @@ import java.util.List;
*/
class AnnotationManager {
- private final NativeMapView nativeMapView;
+ private static final long NO_ANNOTATION_ID = -1;
+
private final MapView mapView;
private final IconManager iconManager;
private final InfoWindowManager infoWindowManager = new InfoWindowManager();
@@ -44,15 +51,18 @@ class AnnotationManager {
private MapboxMap mapboxMap;
private MapboxMap.OnMarkerClickListener onMarkerClickListener;
+ private MapboxMap.OnPolygonClickListener onPolygonClickListener;
+ private MapboxMap.OnPolylineClickListener onPolylineClickListener;
+
private Annotations annotations;
+ private ShapeAnnotations shapeAnnotations;
private Markers markers;
private Polygons polygons;
private Polylines polylines;
AnnotationManager(NativeMapView view, MapView mapView, LongSparseArray<Annotation> annotationsArray,
MarkerViewManager markerViewManager, IconManager iconManager, Annotations annotations,
- Markers markers, Polygons polygons, Polylines polylines) {
- this.nativeMapView = view;
+ Markers markers, Polygons polygons, Polylines polylines, ShapeAnnotations shapeAnnotations) {
this.mapView = mapView;
this.annotationsArray = annotationsArray;
this.markerViewManager = markerViewManager;
@@ -61,9 +71,10 @@ class AnnotationManager {
this.markers = markers;
this.polygons = polygons;
this.polylines = polylines;
+ this.shapeAnnotations = shapeAnnotations;
if (view != null) {
// null checking needed for unit tests
- nativeMapView.addOnMapChangedListener(markerViewManager);
+ view.addOnMapChangedListener(markerViewManager);
}
}
@@ -106,6 +117,9 @@ class AnnotationManager {
if (marker instanceof MarkerView) {
markerViewManager.removeMarkerView((MarkerView) marker);
+ } else {
+ // do icon cleanup
+ iconManager.iconCleanup(marker.getIcon());
}
}
annotations.removeBy(annotation);
@@ -122,6 +136,8 @@ class AnnotationManager {
if (marker instanceof MarkerView) {
markerViewManager.removeMarkerView((MarkerView) marker);
+ } else {
+ iconManager.iconCleanup(marker.getIcon());
}
}
}
@@ -141,6 +157,8 @@ class AnnotationManager {
marker.hideInfoWindow();
if (marker instanceof MarkerView) {
markerViewManager.removeMarkerView((MarkerView) marker);
+ } else {
+ iconManager.iconCleanup(marker.getIcon());
}
}
}
@@ -160,6 +178,10 @@ class AnnotationManager {
}
void updateMarker(@NonNull Marker updatedMarker, @NonNull MapboxMap mapboxMap) {
+ if (!isAddedToMap(updatedMarker)) {
+ logNonAdded(updatedMarker);
+ return;
+ }
markers.update(updatedMarker, mapboxMap);
}
@@ -203,6 +225,10 @@ class AnnotationManager {
}
void updatePolygon(Polygon polygon) {
+ if (!isAddedToMap(polygon)) {
+ logNonAdded(polygon);
+ return;
+ }
polygons.update(polygon);
}
@@ -223,6 +249,10 @@ class AnnotationManager {
}
void updatePolyline(Polyline polyline) {
+ if (!isAddedToMap(polyline)) {
+ logNonAdded(polyline);
+ return;
+ }
polylines.update(polyline);
}
@@ -231,11 +261,18 @@ class AnnotationManager {
}
// TODO Refactor from here still in progress
-
void setOnMarkerClickListener(@Nullable MapboxMap.OnMarkerClickListener listener) {
onMarkerClickListener = listener;
}
+ void setOnPolygonClickListener(@Nullable MapboxMap.OnPolygonClickListener listener) {
+ onPolygonClickListener = listener;
+ }
+
+ void setOnPolylineClickListener(@Nullable MapboxMap.OnPolylineClickListener listener) {
+ onPolylineClickListener = listener;
+ }
+
void selectMarker(@NonNull Marker marker) {
if (selectedMarkers.contains(marker)) {
return;
@@ -325,88 +362,203 @@ class AnnotationManager {
}
}
+ private boolean isAddedToMap(Annotation annotation) {
+ return annotation != null && annotation.getId() != -1 && annotationsArray.indexOfKey(annotation.getId()) > -1;
+ }
+
+ private void logNonAdded(Annotation annotation) {
+ Timber.w("Attempting to update non-added %s with value %s", annotation.getClass().getCanonicalName(), annotation);
+ }
+
//
// Click event
//
- boolean onTap(PointF tapPoint, float screenDensity) {
- float toleranceSides = 4 * screenDensity;
- float toleranceTopBottom = 10 * screenDensity;
- boolean handledDefaultClick = false;
-
- RectF tapRect = new RectF(tapPoint.x - iconManager.getAverageIconWidth() / 2 - toleranceSides,
- tapPoint.y - iconManager.getAverageIconHeight() / 2 - toleranceTopBottom,
- tapPoint.x + iconManager.getAverageIconWidth() / 2 + toleranceSides,
- tapPoint.y + iconManager.getAverageIconHeight() / 2 + toleranceTopBottom);
-
- List<Marker> nearbyMarkers = getMarkersInRect(tapRect);
- long newSelectedMarkerId = -1;
-
- // find a Marker that isn't selected yet
- if (nearbyMarkers.size() > 0) {
- Collections.sort(nearbyMarkers);
- for (Marker nearbyMarker : nearbyMarkers) {
- boolean found = false;
- for (Marker selectedMarker : selectedMarkers) {
- if (selectedMarker.equals(nearbyMarker)) {
- found = true;
- }
- }
- if (!found) {
- newSelectedMarkerId = nearbyMarker.getId();
- break;
- }
+ boolean onTap(PointF tapPoint) {
+ ShapeAnnotationHit shapeAnnotationHit = getShapeAnnotationHitFromTap(tapPoint);
+ Annotation annotation = new ShapeAnnotationHitResolver(shapeAnnotations).execute(shapeAnnotationHit);
+ if (annotation != null) {
+ if (handleClickForShapeAnnotation(annotation)) {
+ return true;
+ }
+ }
+
+ MarkerHit markerHit = getMarkerHitFromTouchArea(tapPoint);
+ long markerId = new MarkerHitResolver(mapboxMap).execute(markerHit);
+ return markerId != NO_ANNOTATION_ID && isClickHandledForMarker(markerId);
+ }
+
+ private ShapeAnnotationHit getShapeAnnotationHitFromTap(PointF tapPoint) {
+ float touchTargetSide = Mapbox.getApplicationContext().getResources().getDimension(R.dimen.mapbox_eight_dp);
+ RectF tapRect = new RectF(
+ tapPoint.x - touchTargetSide,
+ tapPoint.y - touchTargetSide,
+ tapPoint.x + touchTargetSide,
+ tapPoint.y + touchTargetSide
+ );
+ return new ShapeAnnotationHit(tapRect);
+ }
+
+ private boolean handleClickForShapeAnnotation(Annotation annotation) {
+ if (annotation instanceof Polygon && onPolygonClickListener != null) {
+ onPolygonClickListener.onPolygonClick((Polygon) annotation);
+ return true;
+ } else if (annotation instanceof Polyline && onPolylineClickListener != null) {
+ onPolylineClickListener.onPolylineClick((Polyline) annotation);
+ return true;
+ }
+ return false;
+ }
+
+ private MarkerHit getMarkerHitFromTouchArea(PointF tapPoint) {
+ int touchSurfaceWidth = (int) (iconManager.getHighestIconHeight() * 1.5);
+ int touchSurfaceHeight = (int) (iconManager.getHighestIconWidth() * 1.5);
+ final RectF tapRect = new RectF(tapPoint.x - touchSurfaceWidth,
+ tapPoint.y - touchSurfaceHeight,
+ tapPoint.x + touchSurfaceWidth,
+ tapPoint.y + touchSurfaceHeight
+ );
+ return new MarkerHit(tapRect, getMarkersInRect(tapRect));
+ }
+
+ private boolean isClickHandledForMarker(long markerId) {
+ boolean handledDefaultClick;
+ Marker marker = (Marker) getAnnotation(markerId);
+ if (marker instanceof MarkerView) {
+ handledDefaultClick = markerViewManager.onClickMarkerView((MarkerView) marker);
+ } else {
+ handledDefaultClick = onClickMarker(marker);
+ }
+
+ if (!handledDefaultClick) {
+ toggleMarkerSelectionState(marker);
+ }
+ return true;
+ }
+
+ private boolean onClickMarker(Marker marker) {
+ return onMarkerClickListener != null && onMarkerClickListener.onMarkerClick(marker);
+ }
+
+ private void toggleMarkerSelectionState(Marker marker) {
+ if (!selectedMarkers.contains(marker)) {
+ selectMarker(marker);
+ } else {
+ deselectMarker(marker);
+ }
+ }
+
+ private static class ShapeAnnotationHitResolver {
+
+ private ShapeAnnotations shapeAnnotations;
+
+ ShapeAnnotationHitResolver(ShapeAnnotations shapeAnnotations) {
+ this.shapeAnnotations = shapeAnnotations;
+ }
+
+ public Annotation execute(ShapeAnnotationHit shapeHit) {
+ Annotation foundAnnotation = null;
+ List<Annotation> annotations = shapeAnnotations.obtainAllIn(shapeHit.tapPoint);
+ if (annotations.size() > 0) {
+ foundAnnotation = annotations.get(0);
}
+ return foundAnnotation;
+ }
+ }
+
+ private static class MarkerHitResolver {
+
+ private final MarkerViewManager markerViewManager;
+ private final Projection projection;
+
+ private View view;
+ private Bitmap bitmap;
+ private PointF markerLocation;
+
+ private Rect hitRectView = new Rect();
+ private RectF hitRectMarker = new RectF();
+ private RectF highestSurfaceIntersection = new RectF();
+
+ private long closestMarkerId = NO_ANNOTATION_ID;
+
+ MarkerHitResolver(@NonNull MapboxMap mapboxMap) {
+ this.markerViewManager = mapboxMap.getMarkerViewManager();
+ this.projection = mapboxMap.getProjection();
+ }
+
+ public long execute(MarkerHit markerHit) {
+ resolveForMarkers(markerHit);
+ return closestMarkerId;
}
- // if unselected marker found
- if (newSelectedMarkerId >= 0) {
- List<Annotation> annotations = getAnnotations();
- int count = annotations.size();
- for (int i = 0; i < count; i++) {
- Annotation annotation = annotations.get(i);
- if (annotation instanceof Marker) {
- if (annotation.getId() == newSelectedMarkerId) {
- Marker marker = (Marker) annotation;
-
- if (marker instanceof MarkerView) {
- handledDefaultClick = markerViewManager.onClickMarkerView((MarkerView) marker);
- } else {
- if (onMarkerClickListener != null) {
- // end developer has provided a custom click listener
- handledDefaultClick = onMarkerClickListener.onMarkerClick(marker);
- }
- }
-
- if (!handledDefaultClick) {
- // only select marker if user didn't handle the click event themselves
- selectMarker(marker);
- }
-
- return true;
- }
+ private void resolveForMarkers(MarkerHit markerHit) {
+ for (Marker marker : markerHit.markers) {
+ if (marker instanceof MarkerView) {
+ resolveForMarkerView(markerHit, (MarkerView) marker);
+ } else {
+ resolveForMarker(markerHit, marker);
}
}
- } else if (nearbyMarkers.size() > 0) {
- // we didn't find an unselected marker, check if we can close an already open markers
- for (Marker nearbyMarker : nearbyMarkers) {
- for (Marker selectedMarker : selectedMarkers) {
- if (nearbyMarker.equals(selectedMarker)) {
- if (nearbyMarker instanceof MarkerView) {
- handledDefaultClick = markerViewManager.onClickMarkerView((MarkerView) nearbyMarker);
- } else if (onMarkerClickListener != null) {
- handledDefaultClick = onMarkerClickListener.onMarkerClick(nearbyMarker);
- }
-
- if (!handledDefaultClick) {
- // only deselect marker if user didn't handle the click event themselves
- deselectMarker(nearbyMarker);
- }
- return true;
- }
+ }
+
+ private void resolveForMarkerView(MarkerHit markerHit, MarkerView markerView) {
+ view = markerViewManager.getView(markerView);
+ if (view != null) {
+ view.getHitRect(hitRectView);
+ hitRectMarker = new RectF(hitRectView);
+ hitTestMarker(markerHit, markerView, hitRectMarker);
+ }
+ }
+
+ private void resolveForMarker(MarkerHit markerHit, Marker marker) {
+ markerLocation = projection.toScreenLocation(marker.getPosition());
+ bitmap = marker.getIcon().getBitmap();
+ hitRectMarker.set(0, 0, bitmap.getWidth(), bitmap.getHeight());
+ hitRectMarker.offsetTo(
+ markerLocation.x - bitmap.getWidth() / 2,
+ markerLocation.y - bitmap.getHeight() / 2
+ );
+ hitTestMarker(markerHit, marker, hitRectMarker);
+ }
+
+ private void hitTestMarker(MarkerHit markerHit, Marker marker, RectF hitRectMarker) {
+ if (hitRectMarker.contains(markerHit.getTapPointX(), markerHit.getTapPointY())) {
+ hitRectMarker.intersect(markerHit.tapRect);
+ if (isRectangleHighestSurfaceIntersection(hitRectMarker)) {
+ highestSurfaceIntersection = new RectF(hitRectMarker);
+ closestMarkerId = marker.getId();
}
}
}
- return false;
+
+ private boolean isRectangleHighestSurfaceIntersection(RectF rectF) {
+ return rectF.width() * rectF.height() > highestSurfaceIntersection.width() * highestSurfaceIntersection.height();
+ }
+ }
+
+ private static class ShapeAnnotationHit {
+ private final RectF tapPoint;
+
+ ShapeAnnotationHit(RectF tapPoint) {
+ this.tapPoint = tapPoint;
+ }
+ }
+
+ private static class MarkerHit {
+ private final RectF tapRect;
+ private final List<Marker> markers;
+
+ MarkerHit(RectF tapRect, List<Marker> markers) {
+ this.tapRect = tapRect;
+ this.markers = markers;
+ }
+
+ float getTapPointX() {
+ return tapRect.centerX();
+ }
+
+ float getTapPointY() {
+ return tapRect.centerY();
+ }
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java
index 5113a0cc73..9ccff387f5 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java
@@ -1,12 +1,12 @@
package com.mapbox.mapboxsdk.maps;
+import android.app.AlertDialog;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.support.annotation.NonNull;
-import android.support.v7.app.AlertDialog;
import android.text.Html;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
@@ -56,7 +56,7 @@ class AttributionDialogManager implements View.OnClickListener, DialogInterface.
private void showAttributionDialog() {
attributionKeys = attributionMap.keySet().toArray(new String[attributionMap.size()]);
- AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.mapbox_AlertDialogStyle);
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(R.string.mapbox_attributionsDialogTitle);
builder.setAdapter(new ArrayAdapter<>(context, R.layout.mapbox_attribution_list_item, attributionKeys), this);
builder.show();
@@ -77,7 +77,7 @@ class AttributionDialogManager implements View.OnClickListener, DialogInterface.
}
private void showTelemetryDialog() {
- AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.mapbox_AlertDialogStyle);
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(R.string.mapbox_attributionTelemetryTitle);
builder.setMessage(R.string.mapbox_attributionTelemetryMessage);
builder.setPositiveButton(R.string.mapbox_attributionTelemetryPositive, new DialogInterface.OnClickListener() {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java
index bd028aecb6..f046744c31 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcher.java
@@ -1,32 +1,45 @@
package com.mapbox.mapboxsdk.maps;
+import android.support.annotation.NonNull;
+
+import java.util.concurrent.CopyOnWriteArrayList;
+
import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraIdleListener;
import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveCanceledListener;
-import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveStartedListener;
import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveListener;
+import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveStartedListener;
class CameraChangeDispatcher implements MapboxMap.OnCameraMoveStartedListener, MapboxMap.OnCameraMoveListener,
MapboxMap.OnCameraMoveCanceledListener, OnCameraIdleListener {
private boolean idle = true;
+ private final CopyOnWriteArrayList<OnCameraMoveStartedListener> onCameraMoveStarted = new CopyOnWriteArrayList<>();
+ private final CopyOnWriteArrayList<OnCameraMoveCanceledListener> onCameraMoveCanceled = new CopyOnWriteArrayList<>();
+ private final CopyOnWriteArrayList<OnCameraMoveListener> onCameraMove = new CopyOnWriteArrayList<>();
+ private final CopyOnWriteArrayList<OnCameraIdleListener> onCameraIdle = new CopyOnWriteArrayList<>();
+
private OnCameraMoveStartedListener onCameraMoveStartedListener;
private OnCameraMoveCanceledListener onCameraMoveCanceledListener;
private OnCameraMoveListener onCameraMoveListener;
private OnCameraIdleListener onCameraIdleListener;
+ @Deprecated
void setOnCameraMoveStartedListener(OnCameraMoveStartedListener onCameraMoveStartedListener) {
this.onCameraMoveStartedListener = onCameraMoveStartedListener;
}
+ @Deprecated
void setOnCameraMoveCanceledListener(OnCameraMoveCanceledListener onCameraMoveCanceledListener) {
this.onCameraMoveCanceledListener = onCameraMoveCanceledListener;
}
+ @Deprecated
void setOnCameraMoveListener(OnCameraMoveListener onCameraMoveListener) {
this.onCameraMoveListener = onCameraMoveListener;
}
+ @Deprecated
void setOnCameraIdleListener(OnCameraIdleListener onCameraIdleListener) {
this.onCameraIdleListener = onCameraIdleListener;
}
@@ -36,32 +49,106 @@ class CameraChangeDispatcher implements MapboxMap.OnCameraMoveStartedListener, M
if (!idle) {
return;
}
-
idle = false;
+
+ // deprecated API
if (onCameraMoveStartedListener != null) {
onCameraMoveStartedListener.onCameraMoveStarted(reason);
}
+
+ // new API
+ if (!onCameraMoveStarted.isEmpty()) {
+ for (OnCameraMoveStartedListener cameraMoveStartedListener : onCameraMoveStarted) {
+ cameraMoveStartedListener.onCameraMoveStarted(reason);
+ }
+ }
}
@Override
public void onCameraMove() {
+ // deprecated API
if (onCameraMoveListener != null && !idle) {
onCameraMoveListener.onCameraMove();
}
+
+ // new API
+ if (!onCameraMove.isEmpty() && !idle) {
+ for (OnCameraMoveListener cameraMoveListener : onCameraMove) {
+ cameraMoveListener.onCameraMove();
+ }
+ }
}
@Override
public void onCameraMoveCanceled() {
+ // deprecated API
if (onCameraMoveCanceledListener != null && !idle) {
onCameraMoveCanceledListener.onCameraMoveCanceled();
}
+
+ // new API
+ if (!onCameraMoveCanceled.isEmpty() && !idle) {
+ for (OnCameraMoveCanceledListener cameraMoveCanceledListener : onCameraMoveCanceled) {
+ cameraMoveCanceledListener.onCameraMoveCanceled();
+ }
+ }
}
@Override
public void onCameraIdle() {
- if (onCameraIdleListener != null && !idle) {
+ if (!idle) {
idle = true;
- onCameraIdleListener.onCameraIdle();
+ // deprecated API
+ if (onCameraIdleListener != null) {
+ onCameraIdleListener.onCameraIdle();
+ }
+
+ // new API
+ if (!onCameraIdle.isEmpty()) {
+ for (OnCameraIdleListener cameraIdleListener : onCameraIdle) {
+ cameraIdleListener.onCameraIdle();
+ }
+ }
+ }
+ }
+
+ void addOnCameraIdleListener(@NonNull OnCameraIdleListener listener) {
+ onCameraIdle.add(listener);
+ }
+
+ void removeOnCameraIdleListener(@NonNull OnCameraIdleListener listener) {
+ if (onCameraIdle.contains(listener)) {
+ onCameraIdle.remove(listener);
+ }
+ }
+
+ void addOnCameraMoveCancelListener(OnCameraMoveCanceledListener listener) {
+ onCameraMoveCanceled.add(listener);
+ }
+
+ void removeOnCameraMoveCancelListener(OnCameraMoveCanceledListener listener) {
+ if (onCameraMoveCanceled.contains(listener)) {
+ onCameraMoveCanceled.remove(listener);
+ }
+ }
+
+ void addOnCameraMoveStartedListener(OnCameraMoveStartedListener listener) {
+ onCameraMoveStarted.add(listener);
+ }
+
+ void removeOnCameraMoveStartedListener(OnCameraMoveStartedListener listener) {
+ if (onCameraMoveStarted.contains(listener)) {
+ onCameraMoveStarted.remove(listener);
+ }
+ }
+
+ void addOnCameraMoveListener(OnCameraMoveListener listener) {
+ onCameraMove.add(listener);
+ }
+
+ void removeOnCameraMoveListener(OnCameraMoveListener listener) {
+ if (onCameraMove.contains(listener)) {
+ onCameraMove.remove(listener);
}
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java
index 9f4171aee8..80ffa973e7 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java
@@ -7,10 +7,10 @@ import com.mapbox.mapboxsdk.annotations.Icon;
import com.mapbox.mapboxsdk.annotations.IconFactory;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.MarkerView;
-import com.mapbox.mapboxsdk.exceptions.IconBitmapChangedException;
-import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
/**
* Responsible for managing icons added to the Map.
@@ -25,15 +25,14 @@ import java.util.List;
*/
class IconManager {
- private NativeMapView nativeMapView;
- private List<Icon> icons;
+ private final Map<Icon, Integer> iconMap = new HashMap<>();
- private int averageIconHeight;
- private int averageIconWidth;
+ private NativeMapView nativeMapView;
+ private int highestIconWidth;
+ private int highestIconHeight;
IconManager(NativeMapView nativeMapView) {
this.nativeMapView = nativeMapView;
- this.icons = new ArrayList<>();
// load transparent icon for MarkerView to trace actual markers, see #6352
loadIcon(IconFactory.recreate(IconFactory.ICON_MARKERVIEW_ID, IconFactory.ICON_MARKERVIEW_BITMAP));
}
@@ -45,7 +44,7 @@ class IconManager {
// TODO we can move this code afterwards to getIcon as with MarkerView.getIcon
icon = loadDefaultIconForMarker(marker);
} else {
- updateAverageIconSize(icon);
+ updateHighestIconSize(icon);
}
addIcon(icon);
return icon;
@@ -54,7 +53,7 @@ class IconManager {
void loadIconForMarkerView(MarkerView marker) {
Icon icon = marker.getIcon();
Bitmap bitmap = icon.getBitmap();
- updateAverageIconSize(bitmap);
+ updateHighestIconSize(bitmap);
addIcon(icon, false);
}
@@ -62,18 +61,18 @@ class IconManager {
return (int) (nativeMapView.getTopOffsetPixelsForAnnotationSymbol(icon.getId()) * nativeMapView.getPixelRatio());
}
- int getAverageIconHeight() {
- return averageIconHeight;
+ int getHighestIconWidth() {
+ return highestIconWidth;
}
- int getAverageIconWidth() {
- return averageIconWidth;
+ int getHighestIconHeight() {
+ return highestIconHeight;
}
private Icon loadDefaultIconForMarker(Marker marker) {
Icon icon = IconFactory.getInstance(Mapbox.getApplicationContext()).defaultMarker();
Bitmap bitmap = icon.getBitmap();
- updateAverageIconSize(bitmap.getWidth(), bitmap.getHeight() / 2);
+ updateHighestIconSize(bitmap.getWidth(), bitmap.getHeight() / 2);
marker.setIcon(icon);
return icon;
}
@@ -83,28 +82,32 @@ class IconManager {
}
private void addIcon(Icon icon, boolean addIconToMap) {
- if (!icons.contains(icon)) {
- icons.add(icon);
+ if (!iconMap.keySet().contains(icon)) {
+ iconMap.put(icon, 1);
if (addIconToMap) {
loadIcon(icon);
}
} else {
- validateIconChanged(icon);
+ iconMap.put(icon, iconMap.get(icon) + 1);
}
}
- private void updateAverageIconSize(Icon icon) {
- updateAverageIconSize(icon.getBitmap());
+ private void updateHighestIconSize(Icon icon) {
+ updateHighestIconSize(icon.getBitmap());
}
- private void updateAverageIconSize(Bitmap bitmap) {
- updateAverageIconSize(bitmap.getWidth(), bitmap.getHeight());
+ private void updateHighestIconSize(Bitmap bitmap) {
+ updateHighestIconSize(bitmap.getWidth(), bitmap.getHeight());
}
- private void updateAverageIconSize(int width, int height) {
- int iconSize = icons.size() + 1;
- averageIconHeight = averageIconHeight + (height - averageIconHeight) / iconSize;
- averageIconWidth = averageIconWidth + (width - averageIconWidth) / iconSize;
+ private void updateHighestIconSize(int width, int height) {
+ if (width > highestIconWidth) {
+ highestIconWidth = width;
+ }
+
+ if (height > highestIconHeight) {
+ highestIconHeight = height;
+ }
}
private void loadIcon(Icon icon) {
@@ -117,18 +120,11 @@ class IconManager {
}
void reloadIcons() {
- for (Icon icon : icons) {
+ for (Icon icon : iconMap.keySet()) {
loadIcon(icon);
}
}
- private void validateIconChanged(Icon icon) {
- Icon oldIcon = icons.get(icons.indexOf(icon));
- if (!oldIcon.getBitmap().sameAs(icon.getBitmap())) {
- throw new IconBitmapChangedException();
- }
- }
-
void ensureIconLoaded(Marker marker, MapboxMap mapboxMap) {
Icon icon = marker.getIcon();
if (icon == null) {
@@ -145,4 +141,26 @@ class IconManager {
marker.setTopOffsetPixels(getTopOffsetPixelsForIcon(icon));
}
}
+
+ void iconCleanup(Icon icon) {
+ Integer refCounter = iconMap.get(icon);
+ if (refCounter != null) {
+ refCounter--;
+ if (refCounter == 0) {
+ remove(icon);
+ } else {
+ updateIconRefCounter(icon, refCounter);
+ }
+ }
+ }
+
+ private void remove(Icon icon) {
+ nativeMapView.removeAnnotationIcon(icon.getId());
+ iconMap.remove(icon);
+ }
+
+ private void updateIconRefCounter(Icon icon, int refCounter) {
+ iconMap.put(icon, refCounter);
+ }
+
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Image.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Image.java
new file mode 100644
index 0000000000..b2f6cef3b0
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Image.java
@@ -0,0 +1,17 @@
+package com.mapbox.mapboxsdk.maps;
+
+class Image {
+ private final byte[] buffer;
+ private final float pixelRatio;
+ private final String name;
+ private final int width;
+ private final int height;
+
+ public Image(byte[] buffer, float pixelRatio, String name, int width, int height) {
+ this.buffer = buffer;
+ this.pixelRatio = pixelRatio;
+ this.name = name;
+ this.width = width;
+ this.height = height;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/InfoWindowManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/InfoWindowManager.java
index 7599b6afa6..af207204d9 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/InfoWindowManager.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/InfoWindowManager.java
@@ -1,6 +1,5 @@
package com.mapbox.mapboxsdk.maps;
-import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
@@ -22,7 +21,8 @@ import java.util.List;
*/
class InfoWindowManager {
- private List<InfoWindow> infoWindows;
+ private final List<InfoWindow> infoWindows = new ArrayList<>();
+
private MapboxMap.InfoWindowAdapter infoWindowAdapter;
private boolean allowConcurrentMultipleInfoWindows;
@@ -30,13 +30,11 @@ class InfoWindowManager {
private MapboxMap.OnInfoWindowLongClickListener onInfoWindowLongClickListener;
private MapboxMap.OnInfoWindowCloseListener onInfoWindowCloseListener;
- InfoWindowManager() {
- this.infoWindows = new ArrayList<>();
- }
-
void update() {
- for (InfoWindow infoWindow : infoWindows) {
- infoWindow.update();
+ if (!infoWindows.isEmpty()) {
+ for (InfoWindow infoWindow : infoWindows) {
+ infoWindow.update();
+ }
}
}
@@ -56,12 +54,8 @@ class InfoWindowManager {
return allowConcurrentMultipleInfoWindows;
}
- List<InfoWindow> getInfoWindows() {
- return infoWindows;
- }
-
- boolean isInfoWindowValidForMarker(@NonNull Marker marker) {
- return !TextUtils.isEmpty(marker.getTitle()) || !TextUtils.isEmpty(marker.getSnippet());
+ boolean isInfoWindowValidForMarker(Marker marker) {
+ return marker != null && (!TextUtils.isEmpty(marker.getTitle()) || !TextUtils.isEmpty(marker.getSnippet()));
}
void setOnInfoWindowClickListener(@Nullable MapboxMap.OnInfoWindowClickListener listener) {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java
index 8b1ba7b771..01c6da4971 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java
@@ -76,6 +76,9 @@ public final class MapFragment extends Fragment {
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
map.onCreate(savedInstanceState);
+ if (onMapReadyCallback != null) {
+ map.getMapAsync(onMapReadyCallback);
+ }
}
/**
@@ -85,7 +88,6 @@ public final class MapFragment extends Fragment {
public void onStart() {
super.onStart();
map.onStart();
- map.getMapAsync(onMapReadyCallback);
}
/**
@@ -150,6 +152,10 @@ public final class MapFragment extends Fragment {
* @param onMapReadyCallback The callback to be invoked.
*/
public void getMapAsync(@NonNull final OnMapReadyCallback onMapReadyCallback) {
- this.onMapReadyCallback = onMapReadyCallback;
+ if (map == null) {
+ this.onMapReadyCallback = onMapReadyCallback;
+ } else {
+ map.getMapAsync(onMapReadyCallback);
+ }
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java
index 33e13c5ecc..0fea5ce0ff 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java
@@ -1,15 +1,19 @@
package com.mapbox.mapboxsdk.maps;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.PointF;
import android.location.Location;
-import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.view.GestureDetectorCompat;
import android.support.v4.view.ScaleGestureDetectorCompat;
+import android.support.v4.view.animation.FastOutSlowInInterpolator;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
+import android.view.VelocityTracker;
import android.view.ViewConfiguration;
import com.almeros.android.multitouch.gesturedetectors.RotateGestureDetector;
@@ -22,6 +26,8 @@ import com.mapbox.services.android.telemetry.MapboxTelemetry;
import com.mapbox.services.android.telemetry.utils.MathUtils;
import com.mapbox.services.android.telemetry.utils.TelemetryUtils;
+import java.util.concurrent.CopyOnWriteArrayList;
+
import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE;
/**
@@ -39,24 +45,46 @@ final class MapGestureDetector {
private final AnnotationManager annotationManager;
private final CameraChangeDispatcher cameraChangeDispatcher;
- private final GestureDetectorCompat gestureDetector;
- private final ScaleGestureDetector scaleGestureDetector;
- private final RotateGestureDetector rotateGestureDetector;
- private final ShoveGestureDetector shoveGestureDetector;
+ private GestureDetectorCompat gestureDetector;
+ private ScaleGestureDetector scaleGestureDetector;
+ private RotateGestureDetector rotateGestureDetector;
+ private ShoveGestureDetector shoveGestureDetector;
+ // deprecated map touch API
private MapboxMap.OnMapClickListener onMapClickListener;
private MapboxMap.OnMapLongClickListener onMapLongClickListener;
private MapboxMap.OnFlingListener onFlingListener;
private MapboxMap.OnScrollListener onScrollListener;
+ // new map touch API
+ private final CopyOnWriteArrayList<MapboxMap.OnMapClickListener> onMapClickListenerList
+ = new CopyOnWriteArrayList<>();
+
+ private final CopyOnWriteArrayList<MapboxMap.OnMapLongClickListener> onMapLongClickListenerList
+ = new CopyOnWriteArrayList<>();
+
+ private final CopyOnWriteArrayList<MapboxMap.OnFlingListener> onFlingListenerList
+ = new CopyOnWriteArrayList<>();
+
+ private final CopyOnWriteArrayList<MapboxMap.OnScrollListener> onScrollListenerList
+ = new CopyOnWriteArrayList<>();
+
private PointF focalPoint;
- private boolean twoTap = false;
- private boolean zoomStarted = false;
- private boolean dragStarted = false;
- private boolean quickZoom = false;
- private boolean scrollInProgress = false;
- private boolean scaleGestureOccurred = false;
+ private boolean twoTap;
+ private boolean quickZoom;
+ private boolean tiltGestureOccurred;
+ private boolean scrollGestureOccurred;
+
+ private boolean scaleGestureOccurred;
+ private boolean recentScaleGestureOccurred;
+ private boolean scaleAnimating;
+ private long scaleBeginTime;
+
+ private VelocityTracker velocityTracker;
+ private boolean wasZoomingIn;
+ private boolean wasClockwiseRotating;
+ private boolean rotateGestureOccurred;
MapGestureDetector(Context context, Transform transform, Projection projection, UiSettings uiSettings,
TrackingSettings trackingSettings, AnnotationManager annotationManager,
@@ -69,12 +97,14 @@ final class MapGestureDetector {
this.cameraChangeDispatcher = cameraChangeDispatcher;
// Touch gesture detectors
- gestureDetector = new GestureDetectorCompat(context, new GestureListener());
- gestureDetector.setIsLongpressEnabled(true);
- scaleGestureDetector = new ScaleGestureDetector(context, new ScaleGestureListener());
- ScaleGestureDetectorCompat.setQuickScaleEnabled(scaleGestureDetector, true);
- rotateGestureDetector = new RotateGestureDetector(context, new RotateGestureListener());
- shoveGestureDetector = new ShoveGestureDetector(context, new ShoveGestureListener());
+ if (context != null) {
+ gestureDetector = new GestureDetectorCompat(context, new GestureListener());
+ gestureDetector.setIsLongpressEnabled(true);
+ scaleGestureDetector = new ScaleGestureDetector(context, new ScaleGestureListener());
+ ScaleGestureDetectorCompat.setQuickScaleEnabled(scaleGestureDetector, true);
+ rotateGestureDetector = new RotateGestureDetector(context, new RotateGestureListener());
+ shoveGestureDetector = new ShoveGestureDetector(context, new ShoveGestureListener());
+ }
}
/**
@@ -133,22 +163,33 @@ final class MapGestureDetector {
* @param event the MotionEvent
* @return True if touch event is handled
*/
- boolean onTouchEvent(@NonNull MotionEvent event) {
+ boolean onTouchEvent(MotionEvent event) {
+ // framework can return null motion events in edge cases #9432
+ if (event == null) {
+ return false;
+ }
+
// Check and ignore non touch or left clicks
if ((event.getButtonState() != 0) && (event.getButtonState() != MotionEvent.BUTTON_PRIMARY)) {
return false;
}
// Check two finger gestures first
- rotateGestureDetector.onTouchEvent(event);
scaleGestureDetector.onTouchEvent(event);
+ rotateGestureDetector.onTouchEvent(event);
shoveGestureDetector.onTouchEvent(event);
// Handle two finger tap
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
+ if (velocityTracker == null) {
+ velocityTracker = VelocityTracker.obtain();
+ } else {
+ velocityTracker.clear();
+ }
+ velocityTracker.addMovement(event);
// First pointer down, reset scaleGestureOccurred, used to avoid triggering a fling after a scale gesture #7666
- scaleGestureOccurred = false;
+ recentScaleGestureOccurred = false;
transform.setGestureInProgress(true);
break;
@@ -188,20 +229,34 @@ final class MapGestureDetector {
}
// Scroll / Pan Has Stopped
- if (scrollInProgress) {
+ if (scrollGestureOccurred) {
MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapDragEndEvent(
getLocationFromGesture(event.getX(), event.getY()), transform));
- scrollInProgress = false;
+ scrollGestureOccurred = false;
cameraChangeDispatcher.onCameraIdle();
}
twoTap = false;
transform.setGestureInProgress(false);
+ if (velocityTracker != null) {
+ velocityTracker.recycle();
+ }
+ velocityTracker = null;
break;
case MotionEvent.ACTION_CANCEL:
twoTap = false;
transform.setGestureInProgress(false);
+ if (velocityTracker != null) {
+ velocityTracker.recycle();
+ }
+ velocityTracker = null;
+ break;
+ case MotionEvent.ACTION_MOVE:
+ if (velocityTracker != null) {
+ velocityTracker.addMovement(event);
+ velocityTracker.computeCurrentVelocity(1000);
+ }
break;
}
@@ -250,7 +305,6 @@ final class MapGestureDetector {
return false;
}
-
/**
* Responsible for handling one finger gestures.
*/
@@ -274,7 +328,7 @@ final class MapGestureDetector {
break;
case MotionEvent.ACTION_UP:
if (quickZoom) {
- // insert here?
+ cameraChangeDispatcher.onCameraIdle();
quickZoom = false;
break;
}
@@ -310,7 +364,7 @@ final class MapGestureDetector {
@Override
public boolean onSingleTapConfirmed(MotionEvent motionEvent) {
PointF tapPoint = new PointF(motionEvent.getX(), motionEvent.getY());
- boolean tapHandled = annotationManager.onTap(tapPoint, uiSettings.getPixelRatio());
+ boolean tapHandled = annotationManager.onTap(tapPoint);
if (!tapHandled) {
if (uiSettings.isDeselectMarkersOnTap()) {
@@ -318,10 +372,7 @@ final class MapGestureDetector {
annotationManager.deselectMarkers();
}
- // notify app of map click
- if (onMapClickListener != null) {
- onMapClickListener.onMapClick(projection.fromScreenLocation(tapPoint));
- }
+ notifyOnMapClickListeners(tapPoint);
}
MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
@@ -333,20 +384,20 @@ final class MapGestureDetector {
@Override
public void onLongPress(MotionEvent motionEvent) {
- if (onMapLongClickListener != null && !quickZoom) {
- onMapLongClickListener.onMapLongClick(
- projection.fromScreenLocation(new PointF(motionEvent.getX(), motionEvent.getY())));
+ PointF longClickPoint = new PointF(motionEvent.getX(), motionEvent.getY());
+
+ if (!quickZoom) {
+ notifyOnMapLongClickListeners(longClickPoint);
}
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
- if ((!trackingSettings.isScrollGestureCurrentlyEnabled()) || scaleGestureOccurred) {
+ if ((!trackingSettings.isScrollGestureCurrentlyEnabled()) || recentScaleGestureOccurred) {
// don't allow a fling is scroll is disabled
// and ignore when a scale gesture has occurred
return false;
}
- cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
float screenDensity = uiSettings.getPixelRatio();
@@ -362,9 +413,11 @@ final class MapGestureDetector {
// cancel any animation
transform.cancelTransitions();
+ cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
+
// tilt results in a bigger translation, limiting input for #5281
double tilt = transform.getTilt();
- double tiltFactor = 1 + ((tilt != 0) ? (tilt / 10) : 0); /* 1 -> 7 */
+ double tiltFactor = 1.5 + ((tilt != 0) ? (tilt / 10) : 0);
double offsetX = velocityX / tiltFactor / screenDensity;
double offsetY = velocityY / tiltFactor / screenDensity;
@@ -374,9 +427,7 @@ final class MapGestureDetector {
// update transformation
transform.moveBy(offsetX, offsetY, animationTime);
- if (onFlingListener != null) {
- onFlingListener.onFling();
- }
+ notifyOnFlingListeners();
return true;
}
@@ -387,16 +438,19 @@ final class MapGestureDetector {
return false;
}
- if (dragStarted) {
+ if (tiltGestureOccurred) {
return false;
}
- if (!scrollInProgress) {
- scrollInProgress = true;
+ if (!scrollGestureOccurred) {
+ scrollGestureOccurred = true;
// Cancel any animation
- transform.cancelTransitions();
- cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
+ if (!scaleGestureOccurred) {
+ transform.cancelTransitions();
+ cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
+ }
+
MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
getLocationFromGesture(e1.getX(), e1.getY()),
MapboxEvent.GESTURE_PAN_START, transform));
@@ -408,20 +462,69 @@ final class MapGestureDetector {
// Scroll the map
transform.moveBy(-distanceX, -distanceY, 0 /*no duration*/);
- if (onScrollListener != null) {
- onScrollListener.onScroll();
- }
+ notifyOnScrollListeners();
return true;
}
}
+ void notifyOnMapClickListeners(PointF tapPoint) {
+ // deprecated API
+ if (onMapClickListener != null) {
+ onMapClickListener.onMapClick(projection.fromScreenLocation(tapPoint));
+ }
+
+ // new API
+ for (MapboxMap.OnMapClickListener listener : onMapClickListenerList) {
+ listener.onMapClick(projection.fromScreenLocation(tapPoint));
+ }
+ }
+
+ void notifyOnMapLongClickListeners(PointF longClickPoint) {
+ // deprecated API
+ if (onMapLongClickListener != null) {
+ onMapLongClickListener.onMapLongClick(projection.fromScreenLocation(longClickPoint));
+ }
+
+ // new API
+ for (MapboxMap.OnMapLongClickListener listener : onMapLongClickListenerList) {
+ listener.onMapLongClick(projection.fromScreenLocation(longClickPoint));
+ }
+ }
+
+ void notifyOnFlingListeners() {
+ // deprecated API
+ if (onFlingListener != null) {
+ onFlingListener.onFling();
+ }
+
+ // new API
+ for (MapboxMap.OnFlingListener listener : onFlingListenerList) {
+ listener.onFling();
+ }
+ }
+
+ void notifyOnScrollListeners() {
+ //deprecated API
+ if (onScrollListener != null) {
+ onScrollListener.onScroll();
+ }
+
+ // new API
+ for (MapboxMap.OnScrollListener listener : onScrollListenerList) {
+ listener.onScroll();
+ }
+ }
+
/**
* Responsible for handling two finger gestures and double-tap drag gestures.
*/
private class ScaleGestureListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
- long beginTime = 0;
- float scaleFactor = 1.0f;
+ private static final int ANIMATION_TIME_MULTIPLIER = 77;
+ private static final double ZOOM_DISTANCE_DIVIDER = 5;
+
+ private float scaleFactor = 1.0f;
+ private PointF scalePointBegin;
// Called when two fingers first touch the screen
@Override
@@ -430,22 +533,15 @@ final class MapGestureDetector {
return false;
}
- scaleGestureOccurred = true;
- beginTime = detector.getEventTime();
+ recentScaleGestureOccurred = true;
+ scalePointBegin = new PointF(detector.getFocusX(), detector.getFocusY());
+ scaleBeginTime = detector.getEventTime();
MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
getLocationFromGesture(detector.getFocusX(), detector.getFocusY()),
MapboxEvent.GESTURE_PINCH_START, transform));
return true;
}
- // Called when fingers leave screen
- @Override
- public void onScaleEnd(ScaleGestureDetector detector) {
- beginTime = 0;
- scaleFactor = 1.0f;
- zoomStarted = false;
- }
-
// Called each time a finger moves
// Called for pinch zooms and quickzooms/quickscales
@Override
@@ -454,56 +550,126 @@ final class MapGestureDetector {
return super.onScale(detector);
}
- // If scale is large enough ignore a tap
- scaleFactor *= detector.getScaleFactor();
- if ((scaleFactor > 1.05f) || (scaleFactor < 0.95f)) {
- // notify camera change listener
- cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
- zoomStarted = true;
+ wasZoomingIn = (Math.log(detector.getScaleFactor()) / Math.log(Math.PI / 2)) >= 0;
+ if (tiltGestureOccurred) {
+ return false;
}
// Ignore short touches in case it is a tap
// Also ignore small scales
long time = detector.getEventTime();
- long interval = time - beginTime;
- if (!zoomStarted && (interval <= ViewConfiguration.getTapTimeout())) {
+ long interval = time - scaleBeginTime;
+ if (!scaleGestureOccurred && (interval <= ViewConfiguration.getTapTimeout())) {
return false;
}
- if (!zoomStarted) {
- return false;
+ // If scale is large enough ignore a tap
+ scaleFactor *= detector.getScaleFactor();
+ if ((scaleFactor > 1.1f) || (scaleFactor < 0.9f)) {
+ // notify camera change listener
+ cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
+ scaleGestureOccurred = true;
}
- if (dragStarted) {
+ if (!scaleGestureOccurred) {
return false;
}
// Gesture is a quickzoom if there aren't two fingers
+ if (!quickZoom && !twoTap) {
+ cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
+ }
quickZoom = !twoTap;
// make an assumption here; if the zoom center is specified by the gesture, it's NOT going
// to be in the center of the map. Therefore the zoom will translate the map center, so tracking
// should be disabled.
-
trackingSettings.resetTrackingModesIfRequired(!quickZoom, false, false);
// Scale the map
if (focalPoint != null) {
// arround user provided focal point
- transform.zoomBy(Math.log(detector.getScaleFactor()) / Math.log(2), focalPoint.x, focalPoint.y);
+ transform.zoomBy(Math.log(detector.getScaleFactor()) / Math.log(Math.PI / 2), focalPoint.x, focalPoint.y);
} else if (quickZoom) {
+ cameraChangeDispatcher.onCameraMove();
// clamp scale factors we feed to core #7514
- float scaleFactor = MathUtils.clamp(detector.getScaleFactor(),
+ float scaleFactor = detector.getScaleFactor();
+ // around center map
+ double zoomBy = Math.log(scaleFactor) / Math.log(Math.PI / 2);
+ boolean negative = zoomBy < 0;
+ zoomBy = MathUtils.clamp(Math.abs(zoomBy),
MapboxConstants.MINIMUM_SCALE_FACTOR_CLAMP,
MapboxConstants.MAXIMUM_SCALE_FACTOR_CLAMP);
- // around center map
- transform.zoomBy(Math.log(scaleFactor) / Math.log(2), uiSettings.getWidth() / 2, uiSettings.getHeight() / 2);
+ transform.zoomBy(negative ? -zoomBy : zoomBy, uiSettings.getWidth() / 2, uiSettings.getHeight() / 2);
+ recentScaleGestureOccurred = true;
} else {
// around gesture
- transform.zoomBy(Math.log(detector.getScaleFactor()) / Math.log(2), detector.getFocusX(), detector.getFocusY());
+ transform.zoomBy(Math.log(detector.getScaleFactor()) / Math.log(Math.PI / 2),
+ scalePointBegin.x, scalePointBegin.y);
}
-
return true;
}
+
+ // Called when fingers leave screen
+ @Override
+ public void onScaleEnd(final ScaleGestureDetector detector) {
+ if (velocityTracker == null) {
+ return;
+ }
+
+
+ if (rotateGestureOccurred || quickZoom) {
+ reset();
+ return;
+ }
+
+ double velocityXY = Math.abs(velocityTracker.getYVelocity()) + Math.abs(velocityTracker.getXVelocity());
+ if (velocityXY > MapboxConstants.VELOCITY_THRESHOLD_IGNORE_FLING / 2) {
+ scaleAnimating = true;
+ double zoomAddition = calculateScale(velocityXY);
+ double currentZoom = transform.getRawZoom();
+ long animationTime = (long) (Math.log(velocityXY) * ANIMATION_TIME_MULTIPLIER);
+ createScaleAnimator(currentZoom, zoomAddition, animationTime).start();
+ } else if (!scaleAnimating) {
+ reset();
+ }
+ }
+
+ private void reset() {
+ scaleAnimating = false;
+ scaleGestureOccurred = false;
+ scaleBeginTime = 0;
+ scaleFactor = 1.0f;
+ cameraChangeDispatcher.onCameraIdle();
+ }
+
+ private double calculateScale(double velocityXY) {
+ double zoomAddition = (float) (Math.log(velocityXY) / ZOOM_DISTANCE_DIVIDER);
+ if (!wasZoomingIn) {
+ zoomAddition = -zoomAddition;
+ }
+ return zoomAddition;
+ }
+
+ private Animator createScaleAnimator(double currentZoom, double zoomAddition, long animationTime) {
+ ValueAnimator animator = ValueAnimator.ofFloat((float) currentZoom, (float) (currentZoom + zoomAddition));
+ animator.setDuration(animationTime);
+ animator.setInterpolator(new FastOutSlowInInterpolator());
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ transform.setZoom((Float) animation.getAnimatedValue(), scalePointBegin);
+ }
+ });
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ reset();
+ }
+ });
+ return animator;
+ }
}
/**
@@ -511,9 +677,13 @@ final class MapGestureDetector {
*/
private class RotateGestureListener extends RotateGestureDetector.SimpleOnRotateGestureListener {
- long beginTime = 0;
- float totalAngle = 0.0f;
- boolean started = false;
+ private static final float ROTATE_INVOKE_ANGLE = 15.30f;
+ private static final float ROTATE_LIMITATION_ANGLE = 3.35f;
+ private static final float ROTATE_LIMITATION_DURATION = ROTATE_LIMITATION_ANGLE * 1.85f;
+
+ private long beginTime = 0;
+ private boolean started = false;
+ private boolean animating = false;
// Called when two fingers first touch the screen
@Override
@@ -526,54 +696,42 @@ final class MapGestureDetector {
cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
beginTime = detector.getEventTime();
- MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
- getLocationFromGesture(detector.getFocusX(), detector.getFocusY()),
- MapboxEvent.GESTURE_ROTATION_START, transform));
return true;
}
- // Called when the fingers leave the screen
- @Override
- public void onRotateEnd(RotateGestureDetector detector) {
- // notify camera change listener
- beginTime = 0;
- totalAngle = 0.0f;
- started = false;
- }
-
// Called each time one of the two fingers moves
// Called for rotation
@Override
public boolean onRotate(RotateGestureDetector detector) {
- if (!trackingSettings.isRotateGestureCurrentlyEnabled() || dragStarted) {
+ if (!trackingSettings.isRotateGestureCurrentlyEnabled() || tiltGestureOccurred) {
return false;
}
// If rotate is large enough ignore a tap
// Also is zoom already started, don't rotate
- totalAngle += detector.getRotationDegreesDelta();
- if (!zoomStarted && ((totalAngle > 20.0f) || (totalAngle < -20.0f))) {
+ float angle = detector.getRotationDegreesDelta();
+ if (Math.abs(angle) >= ROTATE_INVOKE_ANGLE) {
+ MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
+ getLocationFromGesture(detector.getFocusX(), detector.getFocusY()),
+ MapboxEvent.GESTURE_ROTATION_START, transform));
started = true;
}
- // Ignore short touches in case it is a tap
- // Also ignore small rotate
- long time = detector.getEventTime();
- long interval = time - beginTime;
- if (!started && (interval <= ViewConfiguration.getTapTimeout())) {
+ if (!started) {
return false;
}
- if (!started) {
- return false;
+ wasClockwiseRotating = detector.getRotationDegreesDelta() > 0;
+ if (scaleBeginTime != 0) {
+ rotateGestureOccurred = true;
}
+
// rotation constitutes translation of anything except the center of
// rotation, so cancel both location and bearing tracking if required
trackingSettings.resetTrackingModesIfRequired(true, true, false);
- // Get rotate value
- double bearing = transform.getRawBearing();
- bearing += detector.getRotationDegreesDelta();
+ // Calculate map bearing value
+ double bearing = transform.getRawBearing() + angle;
// Rotate the map
if (focalPoint != null) {
@@ -585,6 +743,83 @@ final class MapGestureDetector {
}
return true;
}
+
+ // Called when the fingers leave the screen
+ @Override
+ public void onRotateEnd(RotateGestureDetector detector) {
+ long interval = detector.getEventTime() - beginTime;
+ if ((!started && (interval <= ViewConfiguration.getTapTimeout())) || scaleAnimating || interval > 500) {
+ reset();
+ return;
+ }
+
+ double angularVelocity = calculateVelocityVector(detector);
+ if (Math.abs(angularVelocity) > 0.001 && rotateGestureOccurred && !animating) {
+ animateRotateVelocity();
+ } else if (!animating) {
+ reset();
+ }
+ }
+
+ private void reset() {
+ beginTime = 0;
+ started = false;
+ animating = false;
+ rotateGestureOccurred = false;
+ }
+
+ private void animateRotateVelocity() {
+ animating = true;
+ double currentRotation = transform.getRawBearing();
+ double rotateAdditionDegrees = calculateVelocityInDegrees();
+ createAnimator(currentRotation, rotateAdditionDegrees).start();
+ }
+
+ private double calculateVelocityVector(RotateGestureDetector detector) {
+ return ((detector.getFocusX() * velocityTracker.getYVelocity())
+ + (detector.getFocusY() * velocityTracker.getXVelocity()))
+ / (Math.pow(detector.getFocusX(), 2) + Math.pow(detector.getFocusY(), 2));
+ }
+
+ private double calculateVelocityInDegrees() {
+ double angleRadians = Math.atan2(velocityTracker.getXVelocity(), velocityTracker.getYVelocity());
+ double angle = angleRadians / (Math.PI / 180);
+ if (angle <= 0) {
+ angle += 360;
+ }
+
+ // limit the angle
+ angle = angle / ROTATE_LIMITATION_ANGLE;
+
+ // correct direction
+ if (!wasClockwiseRotating) {
+ angle = -angle;
+ }
+
+ return angle;
+ }
+
+ private Animator createAnimator(double currentRotation, double rotateAdditionDegrees) {
+ ValueAnimator animator = ValueAnimator.ofFloat(
+ (float) currentRotation,
+ (float) (currentRotation + rotateAdditionDegrees)
+ );
+ animator.setDuration((long) (Math.abs(rotateAdditionDegrees) * ROTATE_LIMITATION_DURATION));
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ transform.setBearing((Float) animation.getAnimatedValue());
+ }
+ });
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ reset();
+ }
+ });
+ return animator;
+ }
}
/**
@@ -592,9 +827,8 @@ final class MapGestureDetector {
*/
private class ShoveGestureListener implements ShoveGestureDetector.OnShoveGestureListener {
- long beginTime = 0;
- float totalDelta = 0.0f;
- boolean started = false;
+ private long beginTime = 0;
+ private float totalDelta = 0.0f;
@Override
public boolean onShoveBegin(ShoveGestureDetector detector) {
@@ -604,10 +838,6 @@ final class MapGestureDetector {
// notify camera change listener
cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
- beginTime = detector.getEventTime();
- MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
- getLocationFromGesture(detector.getFocusX(), detector.getFocusY()),
- MapboxEvent.GESTURE_PITCH_START, transform));
return true;
}
@@ -615,8 +845,7 @@ final class MapGestureDetector {
public void onShoveEnd(ShoveGestureDetector detector) {
beginTime = 0;
totalDelta = 0.0f;
- started = false;
- dragStarted = false;
+ tiltGestureOccurred = false;
}
@Override
@@ -625,22 +854,26 @@ final class MapGestureDetector {
return false;
}
- // If tilt is large enough ignore a tap
- // Also if zoom already started, don't tilt
- totalDelta += detector.getShovePixelsDelta();
- if (!zoomStarted && ((totalDelta > 10.0f) || (totalDelta < -10.0f))) {
- started = true;
- }
-
// Ignore short touches in case it is a tap
// Also ignore small tilt
long time = detector.getEventTime();
long interval = time - beginTime;
- if (!started && (interval <= ViewConfiguration.getTapTimeout())) {
+ if (!tiltGestureOccurred && (interval <= ViewConfiguration.getTapTimeout())) {
return false;
}
- if (!started) {
+ // If tilt is large enough ignore a tap
+ // Also if zoom already started, don't tilt
+ totalDelta += detector.getShovePixelsDelta();
+ if (!tiltGestureOccurred && ((totalDelta > 10.0f) || (totalDelta < -10.0f))) {
+ tiltGestureOccurred = true;
+ beginTime = detector.getEventTime();
+ MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
+ getLocationFromGesture(detector.getFocusX(), detector.getFocusY()),
+ MapboxEvent.GESTURE_PITCH_START, transform));
+ }
+
+ if (!tiltGestureOccurred) {
return false;
}
@@ -651,9 +884,6 @@ final class MapGestureDetector {
// Tilt the map
transform.setTilt(pitch);
-
- dragStarted = true;
-
return true;
}
}
@@ -673,4 +903,36 @@ final class MapGestureDetector {
void setOnScrollListener(MapboxMap.OnScrollListener onScrollListener) {
this.onScrollListener = onScrollListener;
}
+
+ void addOnMapClickListener(MapboxMap.OnMapClickListener onMapClickListener) {
+ onMapClickListenerList.add(onMapClickListener);
+ }
+
+ void removeOnMapClickListener(MapboxMap.OnMapClickListener onMapClickListener) {
+ onMapClickListenerList.remove(onMapClickListener);
+ }
+
+ void addOnMapLongClickListener(MapboxMap.OnMapLongClickListener onMapLongClickListener) {
+ onMapLongClickListenerList.add(onMapLongClickListener);
+ }
+
+ void removeOnMapLongClickListener(MapboxMap.OnMapLongClickListener onMapLongClickListener) {
+ onMapLongClickListenerList.remove(onMapLongClickListener);
+ }
+
+ void addOnFlingListener(MapboxMap.OnFlingListener onFlingListener) {
+ onFlingListenerList.add(onFlingListener);
+ }
+
+ void removeOnFlingListener(MapboxMap.OnFlingListener onFlingListener) {
+ onFlingListenerList.remove(onFlingListener);
+ }
+
+ void addOnScrollListener(MapboxMap.OnScrollListener onScrollListener) {
+ onScrollListenerList.add(onScrollListener);
+ }
+
+ void removeOnScrollListener(MapboxMap.OnScrollListener onScrollListener) {
+ onScrollListenerList.remove(onScrollListener);
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapKeyListener.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapKeyListener.java
index 7175242282..d1f01a30f7 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapKeyListener.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapKeyListener.java
@@ -2,6 +2,7 @@ package com.mapbox.mapboxsdk.maps;
import android.graphics.PointF;
import android.os.Handler;
+import android.os.Looper;
import android.support.annotation.NonNull;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -204,7 +205,7 @@ final class MapKeyListener {
currentTrackballLongPressTimeOut = null;
}
currentTrackballLongPressTimeOut = new TrackballLongPressTimeOut();
- new Handler().postDelayed(currentTrackballLongPressTimeOut,
+ new Handler(Looper.getMainLooper()).postDelayed(currentTrackballLongPressTimeOut,
ViewConfiguration.getLongPressTimeout());
return true;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
index 19cad1d8e0..256f49ef52 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
@@ -1,13 +1,10 @@
package com.mapbox.mapboxsdk.maps;
-import android.app.Activity;
-import android.app.Fragment;
import android.content.Context;
-import android.graphics.Canvas;
import android.graphics.PointF;
-import android.graphics.SurfaceTexture;
+import android.opengl.GLSurfaceView;
+import android.os.Build;
import android.os.Bundle;
-import android.os.Handler;
import android.support.annotation.CallSuper;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
@@ -18,33 +15,40 @@ import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
-import android.view.Surface;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ZoomButtonsController;
-
-import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.annotations.Annotation;
import com.mapbox.mapboxsdk.annotations.MarkerViewManager;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.constants.Style;
+import com.mapbox.mapboxsdk.maps.renderer.MapRenderer;
+import com.mapbox.mapboxsdk.maps.renderer.glsurfaceview.GLSurfaceViewMapRenderer;
+import com.mapbox.mapboxsdk.maps.renderer.textureview.TextureViewMapRenderer;
import com.mapbox.mapboxsdk.maps.widgets.CompassView;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationView;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings;
import com.mapbox.mapboxsdk.net.ConnectivityReceiver;
+import com.mapbox.mapboxsdk.storage.FileSource;
import com.mapbox.services.android.telemetry.MapboxTelemetry;
+import timber.log.Timber;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import static com.mapbox.mapboxsdk.maps.widgets.CompassView.TIME_MAP_NORTH_ANIMATION;
+import static com.mapbox.mapboxsdk.maps.widgets.CompassView.TIME_WAIT_IDLE;
/**
* <p>
@@ -62,17 +66,26 @@ import java.util.List;
*/
public class MapView extends FrameLayout {
+ private final MapCallback mapCallback = new MapCallback();
+ private MapboxMap mapboxMap;
+
private NativeMapView nativeMapView;
- private boolean textureMode;
+ private MapboxMapOptions mapboxMapOptions;
private boolean destroyed;
- private boolean hasSurface;
- private MapboxMap mapboxMap;
- private MapCallback mapCallback;
+ private MyLocationView myLocationView;
+ private CompassView compassView;
+ private PointF focalPoint;
+ private ImageView attrView;
+ private ImageView logoView;
private MapGestureDetector mapGestureDetector;
private MapKeyListener mapKeyListener;
private MapZoomButtonController mapZoomButtonController;
+ private Bundle savedInstanceState;
+ private final CopyOnWriteArrayList<OnMapChangedListener> onMapChangedListeners = new CopyOnWriteArrayList<>();
+
+ private MapRenderer mapRenderer;
@UiThread
public MapView(@NonNull Context context) {
@@ -100,28 +113,42 @@ public class MapView extends FrameLayout {
private void initialise(@NonNull final Context context, @NonNull final MapboxMapOptions options) {
if (isInEditMode()) {
- // in IDE, show preview map
- LayoutInflater.from(context).inflate(R.layout.mapbox_mapview_preview, this);
+ // in IDE layout editor, just return
return;
}
-
- // determine render surface
- textureMode = options.getTextureMode();
+ mapboxMapOptions = options;
// inflate view
View view = LayoutInflater.from(context).inflate(R.layout.mapbox_mapview_internal, this);
- CompassView compassView = (CompassView) view.findViewById(R.id.compassView);
- MyLocationView myLocationView = (MyLocationView) view.findViewById(R.id.userLocationView);
- ImageView attrView = (ImageView) view.findViewById(R.id.attributionView);
+ compassView = (CompassView) view.findViewById(R.id.compassView);
+ myLocationView = (MyLocationView) view.findViewById(R.id.userLocationView);
+ attrView = (ImageView) view.findViewById(R.id.attributionView);
+ logoView = (ImageView) view.findViewById(R.id.logoView);
// add accessibility support
setContentDescription(context.getString(R.string.mapbox_mapActionDescription));
+ setWillNotDraw(false);
- // create native Map object
- nativeMapView = new NativeMapView(this);
+ getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+ getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ } else {
+ getViewTreeObserver().removeGlobalOnLayoutListener(this);
+ }
+ initialiseDrawingSurface(options);
+ }
+ });
+ }
+
+ private void initialiseMap() {
+ Context context = getContext();
+ addOnMapChangedListener(mapCallback);
// callback for focal point invalidation
- FocalPointInvalidator focalPoint = new FocalPointInvalidator(compassView);
+ final FocalPointInvalidator focalPointInvalidator = new FocalPointInvalidator();
+ focalPointInvalidator.addListener(createFocalPointChangeListener());
// callback for registering touch listeners
RegisterTouchListener registerTouchListener = new RegisterTouchListener();
@@ -130,13 +157,15 @@ public class MapView extends FrameLayout {
CameraZoomInvalidator zoomInvalidator = new CameraZoomInvalidator();
// callback for camera change events
- CameraChangeDispatcher cameraChangeDispatcher = new CameraChangeDispatcher();
+ final CameraChangeDispatcher cameraChangeDispatcher = new CameraChangeDispatcher();
// setup components for MapboxMap creation
Projection proj = new Projection(nativeMapView);
- UiSettings uiSettings = new UiSettings(proj, focalPoint, compassView, attrView, view.findViewById(R.id.logoView));
- TrackingSettings trackingSettings = new TrackingSettings(myLocationView, uiSettings, focalPoint, zoomInvalidator);
- MyLocationViewSettings myLocationViewSettings = new MyLocationViewSettings(myLocationView, proj, focalPoint);
+ UiSettings uiSettings = new UiSettings(proj, focalPointInvalidator, compassView, attrView, logoView);
+ TrackingSettings trackingSettings = new TrackingSettings(myLocationView, uiSettings, focalPointInvalidator,
+ zoomInvalidator);
+ MyLocationViewSettings myLocationViewSettings = new MyLocationViewSettings(myLocationView, proj,
+ focalPointInvalidator);
LongSparseArray<Annotation> annotationsArray = new LongSparseArray<>();
MarkerViewManager markerViewManager = new MarkerViewManager((ViewGroup) findViewById(R.id.markerViewContainer));
IconManager iconManager = new IconManager(nativeMapView);
@@ -144,23 +173,32 @@ public class MapView extends FrameLayout {
Markers markers = new MarkerContainer(nativeMapView, this, annotationsArray, iconManager, markerViewManager);
Polygons polygons = new PolygonContainer(nativeMapView, annotationsArray);
Polylines polylines = new PolylineContainer(nativeMapView, annotationsArray);
+ ShapeAnnotations shapeAnnotations = new ShapeAnnotationContainer(nativeMapView, annotationsArray);
AnnotationManager annotationManager = new AnnotationManager(nativeMapView, this, annotationsArray,
- markerViewManager, iconManager, annotations, markers, polygons, polylines);
+ markerViewManager, iconManager, annotations, markers, polygons, polylines, shapeAnnotations);
Transform transform = new Transform(nativeMapView, annotationManager.getMarkerViewManager(), trackingSettings,
cameraChangeDispatcher);
+
mapboxMap = new MapboxMap(nativeMapView, transform, uiSettings, trackingSettings, myLocationViewSettings, proj,
registerTouchListener, annotationManager, cameraChangeDispatcher);
+ focalPointInvalidator.addListener(mapboxMap.createFocalPointChangeListener());
+
+ mapCallback.attachMapboxMap(mapboxMap);
// user input
mapGestureDetector = new MapGestureDetector(context, transform, proj, uiSettings, trackingSettings,
annotationManager, cameraChangeDispatcher);
mapKeyListener = new MapKeyListener(transform, trackingSettings, uiSettings);
- MapZoomControllerListener zoomListener = new MapZoomControllerListener(mapGestureDetector, uiSettings, transform);
- mapZoomButtonController = new MapZoomButtonController(this, uiSettings, zoomListener);
+ // overlain zoom buttons
+ mapZoomButtonController = new MapZoomButtonController(new ZoomButtonsController(this));
+ MapZoomControllerListener zoomListener = new MapZoomControllerListener(mapGestureDetector, uiSettings, transform,
+ cameraChangeDispatcher, getWidth(), getHeight());
+ mapZoomButtonController.bind(uiSettings, zoomListener);
+ compassView.injectCompassAnimationListener(createCompassAnimationListener(cameraChangeDispatcher));
+ compassView.setOnClickListener(createCompassClickListener(cameraChangeDispatcher));
// inject widgets with MapboxMap
- compassView.setMapboxMap(mapboxMap);
myLocationView.setMapboxMap(mapboxMap);
attrView.setOnClickListener(new AttributionDialogManager(context, mapboxMap));
@@ -171,14 +209,58 @@ public class MapView extends FrameLayout {
setFocusableInTouchMode(true);
requestDisallowInterceptTouchEvent(true);
- // allow onDraw invocation
- setWillNotDraw(false);
-
// notify Map object about current connectivity state
nativeMapView.setReachability(ConnectivityReceiver.instance(context).isConnected(context));
// initialise MapboxMap
- mapboxMap.initialise(context, options);
+ if (savedInstanceState == null) {
+ mapboxMap.initialise(context, mapboxMapOptions);
+ } else {
+ mapboxMap.onRestoreInstanceState(savedInstanceState);
+ }
+ }
+
+ private FocalPointChangeListener createFocalPointChangeListener() {
+ return new FocalPointChangeListener() {
+ @Override
+ public void onFocalPointChanged(PointF pointF) {
+ focalPoint = pointF;
+ }
+ };
+ }
+
+ private MapboxMap.OnCompassAnimationListener createCompassAnimationListener(final CameraChangeDispatcher
+ cameraChangeDispatcher) {
+ return new MapboxMap.OnCompassAnimationListener() {
+ @Override
+ public void onCompassAnimation() {
+ cameraChangeDispatcher.onCameraMove();
+ }
+
+ @Override
+ public void onCompassAnimationFinished() {
+ compassView.isAnimating(false);
+ cameraChangeDispatcher.onCameraIdle();
+ }
+ };
+ }
+
+ private OnClickListener createCompassClickListener(final CameraChangeDispatcher cameraChangeDispatcher) {
+ return new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (mapboxMap != null && compassView != null) {
+ if (focalPoint != null) {
+ mapboxMap.setFocalBearing(0, focalPoint.x, focalPoint.y, TIME_MAP_NORTH_ANIMATION);
+ } else {
+ mapboxMap.setFocalBearing(0, mapboxMap.getWidth() / 2, mapboxMap.getHeight() / 2, TIME_MAP_NORTH_ANIMATION);
+ }
+ cameraChangeDispatcher.onCameraMoveStarted(MapboxMap.OnCameraMoveStartedListener.REASON_API_ANIMATION);
+ compassView.isAnimating(true);
+ compassView.postDelayed(compassView, TIME_WAIT_IDLE + TIME_MAP_NORTH_ANIMATION);
+ }
+ }
+ };
}
//
@@ -187,103 +269,160 @@ public class MapView extends FrameLayout {
/**
* <p>
- * You must call this method from the parent's {@link android.app.Activity#onCreate(Bundle)} or
- * {@link android.app.Fragment#onCreate(Bundle)}.
+ * You must call this method from the parent's Activity#onCreate(Bundle)} or
+ * Fragment#onViewCreated(View, Bundle).
* </p>
- * You must set a valid access token with {@link Mapbox#getInstance(Context, String)}) before you call this method
- * or an exception will be thrown.
+ * You must set a valid access token with {@link com.mapbox.mapboxsdk.Mapbox#getInstance(Context, String)}
+ * before you call this method or an exception will be thrown.
*
* @param savedInstanceState Pass in the parent's savedInstanceState.
- * @see Mapbox#getInstance(Context, String)
+ * @see com.mapbox.mapboxsdk.Mapbox#getInstance(Context, String)
*/
@UiThread
public void onCreate(@Nullable Bundle savedInstanceState) {
if (savedInstanceState == null) {
MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapLoadEvent());
} else if (savedInstanceState.getBoolean(MapboxConstants.STATE_HAS_SAVED_STATE)) {
- mapboxMap.onRestoreInstanceState(savedInstanceState);
+ this.savedInstanceState = savedInstanceState;
}
-
- initialiseDrawingSurface(textureMode);
- addOnMapChangedListener(mapCallback = new MapCallback(mapboxMap));
}
- private void initialiseDrawingSurface(boolean textureMode) {
- nativeMapView.initializeDisplay();
- nativeMapView.initializeContext();
- if (textureMode) {
+ private void initialiseDrawingSurface(MapboxMapOptions options) {
+ if (options.getTextureMode()) {
TextureView textureView = new TextureView(getContext());
- textureView.setSurfaceTextureListener(new SurfaceTextureListener());
+ mapRenderer = new TextureViewMapRenderer(getContext(), textureView, options.getLocalIdeographFontFamily()) {
+ @Override
+ protected void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ initRenderSurface();
+ super.onSurfaceCreated(gl, config);
+ }
+ };
+
addView(textureView, 0);
} else {
- SurfaceView surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
- surfaceView.getHolder().addCallback(new SurfaceCallback());
- surfaceView.setVisibility(View.VISIBLE);
+ GLSurfaceView glSurfaceView = (GLSurfaceView) findViewById(R.id.surfaceView);
+ glSurfaceView.setZOrderMediaOverlay(mapboxMapOptions.getRenderSurfaceOnTop());
+ mapRenderer = new GLSurfaceViewMapRenderer(getContext(), glSurfaceView, options.getLocalIdeographFontFamily()) {
+ @Override
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ initRenderSurface();
+ super.onSurfaceCreated(gl, config);
+ }
+ };
+
+ glSurfaceView.setVisibility(View.VISIBLE);
}
+
+ nativeMapView = new NativeMapView(this, mapRenderer);
+ nativeMapView.resizeView(getMeasuredWidth(), getMeasuredHeight());
+ }
+
+ private void initRenderSurface() {
+ post(new Runnable() {
+ @Override
+ public void run() {
+ // Initialise only when not destroyed and only once
+ if (!destroyed && mapboxMap == null) {
+ initialiseMap();
+ mapboxMap.onStart();
+ }
+ }
+ });
}
/**
- * You must call this method from the parent's {@link android.app.Activity#onSaveInstanceState(Bundle)}
- * or {@link android.app.Fragment#onSaveInstanceState(Bundle)}.
+ * You must call this method from the parent's Activity#onSaveInstanceState(Bundle)
+ * or Fragment#onSaveInstanceState(Bundle).
*
* @param outState Pass in the parent's outState.
*/
-
@UiThread
public void onSaveInstanceState(@NonNull Bundle outState) {
- outState.putBoolean(MapboxConstants.STATE_HAS_SAVED_STATE, true);
- mapboxMap.onSaveInstanceState(outState);
+ if (mapboxMap != null) {
+ outState.putBoolean(MapboxConstants.STATE_HAS_SAVED_STATE, true);
+ mapboxMap.onSaveInstanceState(outState);
+ }
}
/**
- * You must call this method from the parent's {@link Activity#onStart()} or {@link Fragment#onStart()}
+ * You must call this method from the parent's Activity#onStart() or Fragment#onStart()
*/
@UiThread
public void onStart() {
- mapboxMap.onStart();
ConnectivityReceiver.instance(getContext()).activate();
+ FileSource.getInstance(getContext()).activate();
+ if (mapboxMap != null) {
+ mapboxMap.onStart();
+ }
+
+ if (mapRenderer != null) {
+ mapRenderer.onStart();
+ }
}
/**
- * You must call this method from the parent's {@link Activity#onResume()} or {@link Fragment#onResume()}.
+ * You must call this method from the parent's Activity#onResume() or Fragment#onResume().
*/
@UiThread
public void onResume() {
- // replaced by onStart in v5.0.0
+ if (mapRenderer != null) {
+ mapRenderer.onResume();
+ }
}
/**
- * You must call this method from the parent's {@link Activity#onPause()} or {@link Fragment#onPause()}.
+ * You must call this method from the parent's Activity#onPause() or Fragment#onPause().
*/
@UiThread
public void onPause() {
- // replaced by onStop in v5.0.0
+ if (mapRenderer != null) {
+ mapRenderer.onPause();
+ }
}
/**
- * You must call this method from the parent's {@link Activity#onStop()} or {@link Fragment#onStop()}.
+ * You must call this method from the parent's Activity#onStop() or Fragment#onStop().
*/
@UiThread
public void onStop() {
- mapboxMap.onStop();
+ if (mapboxMap != null) {
+ // map was destroyed before it was started
+ mapboxMap.onStop();
+ }
+
+ if (mapRenderer != null) {
+ mapRenderer.onStop();
+ }
+
ConnectivityReceiver.instance(getContext()).deactivate();
+ FileSource.getInstance(getContext()).deactivate();
}
/**
- * You must call this method from the parent's {@link Activity#onDestroy()} or {@link Fragment#onDestroy()}.
+ * You must call this method from the parent's Activity#onDestroy() or Fragment#onDestroyView().
*/
@UiThread
public void onDestroy() {
destroyed = true;
- nativeMapView.terminateContext();
- nativeMapView.terminateDisplay();
- nativeMapView.destroySurface();
- nativeMapView.destroy();
- nativeMapView = null;
+ mapCallback.clearOnMapReadyCallbacks();
+
+ if (nativeMapView != null) {
+ // null when destroying an activity programmatically mapbox-navigation-android/issues/503
+ nativeMapView.destroy();
+ nativeMapView = null;
+ }
+
+ if (mapRenderer != null) {
+ mapRenderer.onDestroy();
+ }
}
@Override
public boolean onTouchEvent(MotionEvent event) {
+ if (!isMapInitialized() || !isZoomButtonControllerInitialized()) {
+ return super.onTouchEvent(event);
+ }
+
if (event.getAction() == MotionEvent.ACTION_DOWN) {
mapZoomButtonController.setVisible(true);
}
@@ -312,11 +451,18 @@ public class MapView extends FrameLayout {
@Override
public boolean onGenericMotionEvent(MotionEvent event) {
+ if (mapGestureDetector == null) {
+ return super.onGenericMotionEvent(event);
+ }
return mapGestureDetector.onGenericMotionEvent(event) || super.onGenericMotionEvent(event);
}
@Override
public boolean onHoverEvent(MotionEvent event) {
+ if (!isZoomButtonControllerInitialized()) {
+ return super.onHoverEvent(event);
+ }
+
switch (event.getActionMasked()) {
case MotionEvent.ACTION_HOVER_ENTER:
case MotionEvent.ACTION_HOVER_MOVE:
@@ -334,28 +480,13 @@ public class MapView extends FrameLayout {
}
/**
- * You must call this method from the parent's {@link Activity#onLowMemory()} or {@link Fragment#onLowMemory()}.
+ * You must call this method from the parent's Activity#onLowMemory() or Fragment#onLowMemory().
*/
@UiThread
public void onLowMemory() {
nativeMapView.onLowMemory();
}
- // Called when debug mode is enabled to update a FPS counter
- // Called via JNI from NativeMapView
- // Forward to any listener
- protected void onFpsChanged(final double fps) {
- final MapboxMap.OnFpsChangedListener listener = mapboxMap.getOnFpsChangedListener();
- if (listener != null) {
- post(new Runnable() {
- @Override
- public void run() {
- listener.onFpsChanged(fps);
- }
- });
- }
- }
-
/**
* <p>
* Loads a new map style from the specified URL.
@@ -388,7 +519,10 @@ public class MapView extends FrameLayout {
if (destroyed) {
return;
}
-
+ if (!isMapInitialized()) {
+ mapboxMapOptions.styleUrl(url);
+ return;
+ }
nativeMapView.setStyleUrl(url);
}
@@ -396,119 +530,17 @@ public class MapView extends FrameLayout {
// Rendering
//
- // Called when the map needs to be rerendered
- // Called via JNI from NativeMapView
- protected void onInvalidate() {
- postInvalidate();
- }
-
- @Override
- public void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- if (isInEditMode()) {
- return;
- }
-
- if (destroyed) {
- return;
- }
-
- if (!hasSurface) {
- return;
- }
-
- nativeMapView.render();
- }
-
@Override
protected void onSizeChanged(int width, int height, int oldw, int oldh) {
if (destroyed) {
return;
}
- if (!isInEditMode()) {
+ if (!isInEditMode() && isMapInitialized()) {
nativeMapView.resizeView(width, height);
}
}
- private class SurfaceCallback implements SurfaceHolder.Callback {
-
- private Surface surface;
-
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- nativeMapView.createSurface(surface = holder.getSurface());
- hasSurface = true;
- }
-
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
- if (destroyed) {
- return;
- }
- nativeMapView.resizeFramebuffer(width, height);
- }
-
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- hasSurface = false;
-
- if (nativeMapView != null) {
- nativeMapView.destroySurface();
- }
- surface.release();
- }
- }
-
- // This class handles TextureView callbacks
- private class SurfaceTextureListener implements TextureView.SurfaceTextureListener {
-
- private Surface surface;
-
- // Called when the native surface texture has been created
- // Must do all EGL/GL ES initialization here
- @Override
- public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
- nativeMapView.createSurface(this.surface = new Surface(surface));
- nativeMapView.resizeFramebuffer(width, height);
- hasSurface = true;
- }
-
- // Called when the native surface texture has been destroyed
- // Must do all EGL/GL ES destruction here
- @Override
- public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
- hasSurface = false;
-
- if (nativeMapView != null) {
- nativeMapView.destroySurface();
- }
- this.surface.release();
- return true;
- }
-
- // Called when the format or size of the native surface texture has been changed
- // Must handle window resizing here.
- @Override
- public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
- if (destroyed) {
- return;
- }
-
- nativeMapView.resizeFramebuffer(width, height);
- }
-
- // Called when the SurfaceTexure frame is drawn to screen
- // Must sync with UI here
- @Override
- public void onSurfaceTextureUpdated(SurfaceTexture surface) {
- if (destroyed) {
- return;
- }
- mapboxMap.onUpdateRegionChange();
- }
- }
-
//
// View events
//
@@ -518,7 +550,7 @@ public class MapView extends FrameLayout {
@CallSuper
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- if (mapZoomButtonController != null) {
+ if (isZoomButtonControllerInitialized()) {
mapZoomButtonController.setVisible(false);
}
}
@@ -526,16 +558,29 @@ public class MapView extends FrameLayout {
// Called when view is hidden and shown
@Override
protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
- if (isInEditMode() || mapZoomButtonController == null) {
+ if (isInEditMode()) {
return;
}
- mapZoomButtonController.setVisible(visibility == View.VISIBLE);
+
+ if (isZoomButtonControllerInitialized()) {
+ mapZoomButtonController.setVisible(visibility == View.VISIBLE);
+ }
}
//
// Map events
//
+ void onMapChange(int rawChange) {
+ for (MapView.OnMapChangedListener onMapChangedListener : onMapChangedListeners) {
+ try {
+ onMapChangedListener.onMapChanged(rawChange);
+ } catch (RuntimeException err) {
+ Timber.e(err, "Exception in MapView.OnMapChangedListener");
+ }
+ }
+ }
+
/**
* <p>
* Add a callback that's invoked when the displayed map view changes.
@@ -547,7 +592,7 @@ public class MapView extends FrameLayout {
*/
public void addOnMapChangedListener(@Nullable OnMapChangedListener listener) {
if (listener != null) {
- nativeMapView.addOnMapChangedListener(listener);
+ onMapChangedListeners.add(listener);
}
}
@@ -559,7 +604,7 @@ public class MapView extends FrameLayout {
*/
public void removeOnMapChangedListener(@Nullable OnMapChangedListener listener) {
if (listener != null) {
- nativeMapView.removeOnMapChangedListener(listener);
+ onMapChangedListeners.remove(listener);
}
}
@@ -579,6 +624,14 @@ public class MapView extends FrameLayout {
}
}
+ private boolean isMapInitialized() {
+ return nativeMapView != null;
+ }
+
+ private boolean isZoomButtonControllerInitialized() {
+ return mapZoomButtonController != null;
+ }
+
MapboxMap getMapboxMap() {
return mapboxMap;
}
@@ -783,7 +836,7 @@ public class MapView extends FrameLayout {
public static final int DID_FINISH_LOADING_STYLE = 14;
/**
- * This {@link MapChange} is triggered when a source attribution changes.
+ * This {@link MapChange} is triggered when a source changes.
* <p>
* Register to {@link MapChange} events with {@link MapView#addOnMapChangedListener(OnMapChangedListener)}.
* </p>
@@ -826,10 +879,10 @@ public class MapView extends FrameLayout {
private class FocalPointInvalidator implements FocalPointChangeListener {
- private final FocalPointChangeListener[] focalPointChangeListeners;
+ private final List<FocalPointChangeListener> focalPointChangeListeners = new ArrayList<>();
- FocalPointInvalidator(FocalPointChangeListener... listeners) {
- focalPointChangeListeners = listeners;
+ void addListener(FocalPointChangeListener focalPointChangeListener) {
+ focalPointChangeListeners.add(focalPointChangeListener);
}
@Override
@@ -844,36 +897,83 @@ public class MapView extends FrameLayout {
private class RegisterTouchListener implements MapboxMap.OnRegisterTouchListener {
@Override
- public void onRegisterMapClickListener(MapboxMap.OnMapClickListener listener) {
+ public void onSetMapClickListener(MapboxMap.OnMapClickListener listener) {
mapGestureDetector.setOnMapClickListener(listener);
}
@Override
- public void onRegisterMapLongClickListener(MapboxMap.OnMapLongClickListener listener) {
+ public void onAddMapClickListener(MapboxMap.OnMapClickListener listener) {
+ mapGestureDetector.addOnMapClickListener(listener);
+ }
+
+ @Override
+ public void onRemoveMapClickListener(MapboxMap.OnMapClickListener listener) {
+ mapGestureDetector.removeOnMapClickListener(listener);
+ }
+
+ @Override
+ public void onSetMapLongClickListener(MapboxMap.OnMapLongClickListener listener) {
mapGestureDetector.setOnMapLongClickListener(listener);
}
@Override
- public void onRegisterScrollListener(MapboxMap.OnScrollListener listener) {
+ public void onAddMapLongClickListener(MapboxMap.OnMapLongClickListener listener) {
+ mapGestureDetector.addOnMapLongClickListener(listener);
+ }
+
+ @Override
+ public void onRemoveMapLongClickListener(MapboxMap.OnMapLongClickListener listener) {
+ mapGestureDetector.removeOnMapLongClickListener(listener);
+ }
+
+ @Override
+ public void onSetScrollListener(MapboxMap.OnScrollListener listener) {
mapGestureDetector.setOnScrollListener(listener);
}
@Override
- public void onRegisterFlingListener(MapboxMap.OnFlingListener listener) {
+ public void onAddScrollListener(MapboxMap.OnScrollListener listener) {
+ mapGestureDetector.addOnScrollListener(listener);
+ }
+
+ @Override
+ public void onRemoveScrollListener(MapboxMap.OnScrollListener listener) {
+ mapGestureDetector.removeOnScrollListener(listener);
+ }
+
+ @Override
+ public void onSetFlingListener(MapboxMap.OnFlingListener listener) {
mapGestureDetector.setOnFlingListener(listener);
}
+
+ @Override
+ public void onAddFlingListener(MapboxMap.OnFlingListener listener) {
+ mapGestureDetector.addOnFlingListener(listener);
+ }
+
+ @Override
+ public void onRemoveFlingListener(MapboxMap.OnFlingListener listener) {
+ mapGestureDetector.removeOnFlingListener(listener);
+ }
}
- private class MapZoomControllerListener implements ZoomButtonsController.OnZoomListener {
+ private static class MapZoomControllerListener implements ZoomButtonsController.OnZoomListener {
private final MapGestureDetector mapGestureDetector;
private final UiSettings uiSettings;
private final Transform transform;
+ private final CameraChangeDispatcher cameraChangeDispatcher;
+ private final float mapWidth;
+ private final float mapHeight;
- MapZoomControllerListener(MapGestureDetector detector, UiSettings uiSettings, Transform transform) {
+ MapZoomControllerListener(MapGestureDetector detector, UiSettings uiSettings, Transform transform,
+ CameraChangeDispatcher dispatcher, float mapWidth, float mapHeight) {
this.mapGestureDetector = detector;
this.uiSettings = uiSettings;
this.transform = transform;
+ this.cameraChangeDispatcher = dispatcher;
+ this.mapWidth = mapWidth;
+ this.mapHeight = mapHeight;
}
// Not used
@@ -886,6 +986,7 @@ public class MapView extends FrameLayout {
@Override
public void onZoom(boolean zoomIn) {
if (uiSettings.isZoomGesturesEnabled()) {
+ cameraChangeDispatcher.onCameraMoveStarted(CameraChangeDispatcher.REASON_API_ANIMATION);
onZoom(zoomIn, mapGestureDetector.getFocalPoint());
}
}
@@ -894,7 +995,7 @@ public class MapView extends FrameLayout {
if (focalPoint != null) {
transform.zoom(zoomIn, focalPoint);
} else {
- PointF centerPoint = new PointF(getMeasuredWidth() / 2, getMeasuredHeight() / 2);
+ PointF centerPoint = new PointF(mapWidth / 2, mapHeight / 2);
transform.zoom(zoomIn, centerPoint);
}
}
@@ -923,11 +1024,11 @@ public class MapView extends FrameLayout {
private static class MapCallback implements OnMapChangedListener {
- private final MapboxMap mapboxMap;
+ private MapboxMap mapboxMap;
private final List<OnMapReadyCallback> onMapReadyCallbackList = new ArrayList<>();
private boolean initialLoad = true;
- MapCallback(MapboxMap mapboxMap) {
+ void attachMapboxMap(MapboxMap mapboxMap) {
this.mapboxMap = mapboxMap;
}
@@ -935,14 +1036,9 @@ public class MapView extends FrameLayout {
public void onMapChanged(@MapChange int change) {
if (change == DID_FINISH_LOADING_STYLE && initialLoad) {
initialLoad = false;
- new Handler().post(new Runnable() {
- @Override
- public void run() {
- mapboxMap.onPreMapReady();
- onMapReady();
- mapboxMap.onPostMapReady();
- }
- });
+ mapboxMap.onPreMapReady();
+ onMapReady();
+ mapboxMap.onPostMapReady();
} else if (change == DID_FINISH_RENDERING_FRAME || change == DID_FINISH_RENDERING_FRAME_FULLY_RENDERED) {
mapboxMap.onUpdateFullyRendered();
} else if (change == REGION_IS_CHANGING || change == REGION_DID_CHANGE || change == DID_FINISH_LOADING_MAP) {
@@ -969,5 +1065,9 @@ public class MapView extends FrameLayout {
void addOnMapReadyCallback(OnMapReadyCallback callback) {
onMapReadyCallbackList.add(callback);
}
+
+ void clearOnMapReadyCallbacks() {
+ onMapReadyCallbackList.clear();
+ }
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapZoomButtonController.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapZoomButtonController.java
index 16513904c5..018c8eb5bb 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapZoomButtonController.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapZoomButtonController.java
@@ -1,7 +1,6 @@
package com.mapbox.mapboxsdk.maps;
import android.support.annotation.NonNull;
-import android.view.View;
import android.widget.ZoomButtonsController;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
@@ -12,21 +11,25 @@ import com.mapbox.mapboxsdk.constants.MapboxConstants;
* Allows single touch only devices to zoom in and out.
* </p>
*/
-final class MapZoomButtonController extends ZoomButtonsController {
+final class MapZoomButtonController {
private UiSettings uiSettings;
+ private ZoomButtonsController zoomButtonsController;
- MapZoomButtonController(@NonNull View ownerView, @NonNull UiSettings uiSettings, @NonNull OnZoomListener listener) {
- super(ownerView);
+ MapZoomButtonController(@NonNull ZoomButtonsController zoomButtonsController) {
+ this.zoomButtonsController = zoomButtonsController;
+ this.zoomButtonsController.setZoomSpeed(MapboxConstants.ANIMATION_DURATION);
+ }
+
+ void bind(UiSettings uiSettings, ZoomButtonsController.OnZoomListener onZoomListener) {
this.uiSettings = uiSettings;
- setZoomSpeed(MapboxConstants.ANIMATION_DURATION);
- setOnZoomListener(listener);
+ zoomButtonsController.setOnZoomListener(onZoomListener);
}
- @Override
- public void setVisible(boolean visible) {
- if (uiSettings.isZoomControlsEnabled()) {
- super.setVisible(visible);
+ void setVisible(boolean visible) {
+ if (uiSettings != null && !uiSettings.isZoomControlsEnabled()) {
+ return;
}
+ zoomButtonsController.setVisible(visible);
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java
index f60ddf616a..bf98e6bbc1 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java
@@ -37,7 +37,6 @@ import com.mapbox.mapboxsdk.constants.MyLocationTracking;
import com.mapbox.mapboxsdk.constants.Style;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
-import com.mapbox.mapboxsdk.location.LocationSource;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings;
import com.mapbox.mapboxsdk.style.layers.Filter;
import com.mapbox.mapboxsdk.style.layers.Layer;
@@ -45,8 +44,10 @@ import com.mapbox.mapboxsdk.style.light.Light;
import com.mapbox.mapboxsdk.style.sources.Source;
import com.mapbox.services.android.telemetry.location.LocationEngine;
import com.mapbox.services.commons.geojson.Feature;
+import com.mapbox.services.commons.geojson.Geometry;
import java.lang.reflect.ParameterizedType;
+import java.util.HashMap;
import java.util.List;
import timber.log.Timber;
@@ -60,6 +61,7 @@ import timber.log.Timber;
* Note: Similar to a View object, a MapboxMap should only be read and modified from the main thread.
* </p>
*/
+@UiThread
public final class MapboxMap {
private final NativeMapView nativeMapView;
@@ -75,6 +77,7 @@ public final class MapboxMap {
private final OnRegisterTouchListener onRegisterTouchListener;
private MapboxMap.OnFpsChangedListener onFpsChangedListener;
+ private PointF focalPoint;
MapboxMap(NativeMapView map, Transform transform, UiSettings ui, TrackingSettings tracking,
MyLocationViewSettings myLocationView, Projection projection, OnRegisterTouchListener listener,
@@ -100,6 +103,7 @@ public final class MapboxMap {
setDebugActive(options.getDebugActive());
setApiBaseUrl(options);
setStyleUrl(options);
+ setPrefetchesTiles(options);
}
/**
@@ -132,6 +136,7 @@ public final class MapboxMap {
outState.putString(MapboxConstants.STATE_STYLE_URL, nativeMapView.getStyleUrl());
trackingSettings.onSaveInstanceState(outState);
uiSettings.onSaveInstanceState(outState);
+ myLocationViewSettings.onSaveInstanceState(outState);
}
/**
@@ -141,12 +146,17 @@ public final class MapboxMap {
*/
void onRestoreInstanceState(Bundle savedInstanceState) {
final CameraPosition cameraPosition = savedInstanceState.getParcelable(MapboxConstants.STATE_CAMERA_POSITION);
- if (cameraPosition != null) {
- moveCamera(CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder(cameraPosition).build()));
- }
+ myLocationViewSettings.onRestoreInstanceState(savedInstanceState);
uiSettings.onRestoreInstanceState(savedInstanceState);
trackingSettings.onRestoreInstanceState(savedInstanceState);
+
+ if (cameraPosition != null) {
+ moveCamera(CameraUpdateFactory.newCameraPosition(
+ new CameraPosition.Builder(cameraPosition).build())
+ );
+ }
+
nativeMapView.setDebug(savedInstanceState.getBoolean(MapboxConstants.STATE_DEBUG_ACTIVE));
final String styleUrl = savedInstanceState.getString(MapboxConstants.STATE_STYLE_URL);
@@ -202,7 +212,6 @@ public final class MapboxMap {
*
* @return Duration in milliseconds
*/
- @UiThread
public long getTransitionDuration() {
return nativeMapView.getTransitionDuration();
}
@@ -212,7 +221,6 @@ public final class MapboxMap {
*
* @param durationMs Duration in milliseconds
*/
- @UiThread
public void setTransitionDuration(long durationMs) {
nativeMapView.setTransitionDuration(durationMs);
}
@@ -225,7 +233,6 @@ public final class MapboxMap {
*
* @return Delay in milliseconds
*/
- @UiThread
public long getTransitionDelay() {
return nativeMapView.getTransitionDelay();
}
@@ -235,17 +242,44 @@ public final class MapboxMap {
*
* @param delayMs Delay in milliseconds
*/
- @UiThread
public void setTransitionDelay(long delayMs) {
nativeMapView.setTransitionDelay(delayMs);
}
/**
+ * Sets tile pre-fetching from MapboxOptions.
+ *
+ * @param options the options object
+ */
+ private void setPrefetchesTiles(@NonNull MapboxMapOptions options) {
+ setPrefetchesTiles(options.getPrefetchesTiles());
+ }
+
+ /**
+ * Enable or disable tile pre-fetching. Pre-fetching makes sure that a low-resolution
+ * tile is rendered as soon as possible at the expense of a little bandwidth.
+ *
+ * @param enable true to enable
+ */
+ public void setPrefetchesTiles(boolean enable) {
+ nativeMapView.setPrefetchesTiles(enable);
+ }
+
+ /**
+ * Check whether tile pre-fetching is enabled or not.
+ *
+ * @return true if enabled
+ * @see MapboxMap#setPrefetchesTiles(boolean)
+ */
+ public boolean getPrefetchesTiles() {
+ return nativeMapView.getPrefetchesTiles();
+ }
+
+ /**
* Retrieve all the layers in the style
*
* @return all the layers in the current style
*/
- @UiThread
public List<Layer> getLayers() {
return nativeMapView.getLayers();
}
@@ -257,7 +291,6 @@ public final class MapboxMap {
* @return the layer, if present in the style
*/
@Nullable
- @UiThread
public Layer getLayer(@NonNull String layerId) {
return nativeMapView.getLayer(layerId);
}
@@ -270,13 +303,12 @@ public final class MapboxMap {
* @return the casted Layer, null if another type
*/
@Nullable
- @UiThread
public <T extends Layer> T getLayerAs(@NonNull String layerId) {
try {
// noinspection unchecked
return (T) nativeMapView.getLayer(layerId);
} catch (ClassCastException exception) {
- Timber.e(String.format("Layer: %s is a different type: %s", layerId, exception));
+ Timber.e(exception, "Layer: %s is a different type: ", layerId);
return null;
}
}
@@ -286,7 +318,6 @@ public final class MapboxMap {
*
* @param layer the layer to add
*/
- @UiThread
public void addLayer(@NonNull Layer layer) {
nativeMapView.addLayer(layer);
}
@@ -297,7 +328,6 @@ public final class MapboxMap {
* @param layer the layer to add
* @param below the layer id to add this layer before
*/
- @UiThread
public void addLayerBelow(@NonNull Layer layer, @NonNull String below) {
nativeMapView.addLayerBelow(layer, below);
}
@@ -308,7 +338,6 @@ public final class MapboxMap {
* @param layer the layer to add
* @param above the layer id to add this layer above
*/
- @UiThread
public void addLayerAbove(@NonNull Layer layer, @NonNull String above) {
nativeMapView.addLayerAbove(layer, above);
}
@@ -320,7 +349,6 @@ public final class MapboxMap {
* @param layer the layer to add
* @param index the index to insert the layer at
*/
- @UiThread
public void addLayerAt(@NonNull Layer layer, @IntRange(from = 0) int index) {
nativeMapView.addLayerAt(layer, index);
}
@@ -331,7 +359,6 @@ public final class MapboxMap {
* @param layerId the layer to remove
* @return the removed layer or null if not found
*/
- @UiThread
@Nullable
public Layer removeLayer(@NonNull String layerId) {
return nativeMapView.removeLayer(layerId);
@@ -343,7 +370,6 @@ public final class MapboxMap {
* @param layer the layer to remove
* @return the layer
*/
- @UiThread
@Nullable
public Layer removeLayer(@NonNull Layer layer) {
return nativeMapView.removeLayer(layer);
@@ -355,7 +381,6 @@ public final class MapboxMap {
* @param index the layer index
* @return the removed layer or null if not found
*/
- @UiThread
@Nullable
public Layer removeLayerAt(@IntRange(from = 0) int index) {
return nativeMapView.removeLayerAt(index);
@@ -366,7 +391,6 @@ public final class MapboxMap {
*
* @return all the sources in the current style
*/
- @UiThread
public List<Source> getSources() {
return nativeMapView.getSources();
}
@@ -378,7 +402,6 @@ public final class MapboxMap {
* @return the source if present in the current style
*/
@Nullable
- @UiThread
public Source getSource(@NonNull String sourceId) {
return nativeMapView.getSource(sourceId);
}
@@ -391,13 +414,12 @@ public final class MapboxMap {
* @return the casted Source, null if another type
*/
@Nullable
- @UiThread
public <T extends Source> T getSourceAs(@NonNull String sourceId) {
try {
// noinspection unchecked
return (T) nativeMapView.getSource(sourceId);
} catch (ClassCastException exception) {
- Timber.e(String.format("Source: %s is a different type: %s", sourceId, exception));
+ Timber.e(exception, "Source: %s is a different type: ", sourceId);
return null;
}
}
@@ -407,7 +429,6 @@ public final class MapboxMap {
*
* @param source the source to add
*/
- @UiThread
public void addSource(@NonNull Source source) {
nativeMapView.addSource(source);
}
@@ -418,7 +439,6 @@ public final class MapboxMap {
* @param sourceId the source to remove
* @return the source handle or null if the source was not present
*/
- @UiThread
@Nullable
public Source removeSource(@NonNull String sourceId) {
return nativeMapView.removeSource(sourceId);
@@ -430,7 +450,6 @@ public final class MapboxMap {
* @param source the source to remove
* @return the source
*/
- @UiThread
@Nullable
public Source removeSource(@NonNull Source source) {
return nativeMapView.removeSource(source);
@@ -442,21 +461,30 @@ public final class MapboxMap {
* @param name the name of the image
* @param image the pre-multiplied Bitmap
*/
- @UiThread
public void addImage(@NonNull String name, @NonNull Bitmap image) {
nativeMapView.addImage(name, image);
}
/**
+ * Adds an images to be used in the map's style
+ */
+ public void addImages(@NonNull HashMap<String, Bitmap> images) {
+ nativeMapView.addImages(images);
+ }
+
+ /**
* Removes an image from the map's style
*
* @param name the name of the image to remove
*/
- @UiThread
public void removeImage(String name) {
nativeMapView.removeImage(name);
}
+ public Bitmap getImage(@NonNull String name) {
+ return nativeMapView.getImage(name);
+ }
+
//
// MinZoom
//
@@ -468,7 +496,6 @@ public final class MapboxMap {
*
* @param minZoom The new minimum zoom level.
*/
- @UiThread
public void setMinZoomPreference(
@FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double minZoom) {
transform.setMinZoom(minZoom);
@@ -476,12 +503,11 @@ public final class MapboxMap {
/**
* <p>
- * Gets the maximum zoom level the map can be displayed at.
+ * Gets the minimum zoom level the map can be displayed at.
* </p>
*
* @return The minimum zoom level.
*/
- @UiThread
public double getMinZoomLevel() {
return transform.getMinZoom();
}
@@ -494,10 +520,12 @@ public final class MapboxMap {
* <p>
* Sets the maximum zoom level the map can be displayed at.
* </p>
+ * <p>
+ * The default maximum zoomn level is 22. The upper bound for this value is 25.5.
+ * </p>
*
* @param maxZoom The new maximum zoom level.
*/
- @UiThread
public void setMaxZoomPreference(@FloatRange(from = MapboxConstants.MINIMUM_ZOOM,
to = MapboxConstants.MAXIMUM_ZOOM) double maxZoom) {
transform.setMaxZoom(maxZoom);
@@ -510,7 +538,6 @@ public final class MapboxMap {
*
* @return The maximum zoom level.
*/
- @UiThread
public double getMaxZoomLevel() {
return transform.getMaxZoom();
}
@@ -536,7 +563,10 @@ public final class MapboxMap {
* Gets the tracking interface settings for the map.
*
* @return the TrackingSettings asssociated with this map
+ * @deprecated use location layer plugin from
+ * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugin-locationlayer instead.
*/
+ @Deprecated
public TrackingSettings getTrackingSettings() {
return trackingSettings;
}
@@ -549,7 +579,10 @@ public final class MapboxMap {
* Gets the settings of the user location for the map.
*
* @return the MyLocationViewSettings associated with this map
+ * @deprecated use location layer plugin from
+ * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugin-locationlayer instead.
*/
+ @Deprecated
public MyLocationViewSettings getMyLocationViewSettings() {
return myLocationViewSettings;
}
@@ -587,6 +620,47 @@ public final class MapboxMap {
//
/**
+ * Moves the center of the screen to a latitude and longitude specified by a LatLng object. This centers the
+ * camera on the LatLng object.
+ *
+ * @param latLng Target location to change to
+ */
+ public void setLatLng(@NonNull LatLng latLng) {
+ nativeMapView.setLatLng(latLng);
+ }
+
+ /**
+ * Moves the camera viewpoint to a particular zoom level.
+ *
+ * @param zoom Zoom level to change to
+ */
+ public void setZoom(@FloatRange(from = MapboxConstants.MINIMUM_ZOOM, to = MapboxConstants.MAXIMUM_ZOOM) double zoom) {
+ if (focalPoint == null) {
+ focalPoint = new PointF(nativeMapView.getWidth() / 2, nativeMapView.getHeight() / 2);
+ }
+ nativeMapView.setZoom(zoom, focalPoint, 0);
+ }
+
+ /**
+ * Moves the camera viewpoint angle to a particular angle in degrees.
+ *
+ * @param tilt Tilt angle to change to
+ */
+ public void setTilt(@FloatRange(from = MapboxConstants.MINIMUM_TILT, to = MapboxConstants.MAXIMUM_TILT) double tilt) {
+ nativeMapView.setPitch(tilt, 0);
+ }
+
+ /**
+ * Moves the camera viewpoint direction to a particular angle in degrees.
+ *
+ * @param bearing Direction angle to change to
+ */
+ public void setBearing(@FloatRange(from = MapboxConstants.MINIMUM_DIRECTION, to = MapboxConstants.MAXIMUM_DIRECTION)
+ double bearing) {
+ nativeMapView.setBearing(bearing);
+ }
+
+ /**
* Cancels ongoing animations.
* <p>
* This invokes the {@link CancelableCallback} for ongoing camera updates.
@@ -625,7 +699,6 @@ public final class MapboxMap {
*
* @param update The change that should be applied to the camera.
*/
- @UiThread
public final void moveCamera(CameraUpdate update) {
moveCamera(update, null);
}
@@ -638,7 +711,6 @@ public final class MapboxMap {
* @param update The change that should be applied to the camera
* @param callback the callback to be invoked when an animation finishes or is canceled
*/
- @UiThread
public final void moveCamera(final CameraUpdate update, final MapboxMap.CancelableCallback callback) {
new Handler().post(new Runnable() {
@Override
@@ -647,6 +719,10 @@ public final class MapboxMap {
// MapChange.REGION_DID_CHANGE_ANIMATED is not called for `jumpTo`
// invalidate camera position to provide OnCameraChange event.
invalidateCameraPosition();
+
+ if (callback != null) {
+ callback.onFinish();
+ }
}
});
}
@@ -659,7 +735,6 @@ public final class MapboxMap {
* @param update The change that should be applied to the camera.
* @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
- @UiThread
public final void easeCamera(CameraUpdate update) {
easeCamera(update, MapboxConstants.ANIMATION_DURATION);
}
@@ -674,7 +749,6 @@ public final class MapboxMap {
* positive, otherwise an IllegalArgumentException will be thrown.
* @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
- @UiThread
public final void easeCamera(CameraUpdate update, int durationMs) {
easeCamera(update, durationMs, null);
}
@@ -698,7 +772,6 @@ public final class MapboxMap {
* Do not update or ease the camera from within onCancel().
* @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
- @UiThread
public final void easeCamera(CameraUpdate update, int durationMs, final MapboxMap.CancelableCallback callback) {
easeCamera(update, durationMs, true, callback);
}
@@ -717,7 +790,6 @@ public final class MapboxMap {
* positive, otherwise an IllegalArgumentException will be thrown.
* @param easingInterpolator True for easing interpolator, false for linear.
*/
- @UiThread
public final void easeCamera(CameraUpdate update, int durationMs, boolean easingInterpolator) {
easeCamera(update, durationMs, easingInterpolator, null);
}
@@ -729,8 +801,8 @@ public final class MapboxMap {
* will return the current location of the camera in flight.
* <p>
* Note that this will cancel location tracking mode if enabled. You can change this behaviour by calling
- * {@link TrackingSettings#setDismissTrackingModeForCameraPositionChange(boolean)} with false before invoking this
- * method and calling it with true in the {@link CancelableCallback#onFinish()}.
+ * {@link com.mapbox.mapboxsdk.maps.TrackingSettings#setDismissLocationTrackingOnGesture(boolean)} with false before
+ * invoking this method and calling it with true in the {@link CancelableCallback#onFinish()}.
* </p>
*
* @param update The change that should be applied to the camera.
@@ -743,7 +815,6 @@ public final class MapboxMap {
* by a later camera movement or a user gesture, onCancel() will be called.
* Do not update or ease the camera from within onCancel().
*/
- @UiThread
public final void easeCamera(final CameraUpdate update, final int durationMs, final boolean easingInterpolator,
final MapboxMap.CancelableCallback callback) {
easeCamera(update, durationMs, easingInterpolator, callback, false);
@@ -756,8 +827,8 @@ public final class MapboxMap {
* will return the current location of the camera in flight.
* <p>
* Note that this will cancel location tracking mode if enabled. You can change this behaviour by calling
- * {@link TrackingSettings#setDismissTrackingModeForCameraPositionChange(boolean)} with false before invoking this
- * method and calling it with true in the {@link CancelableCallback#onFinish()}.
+ * {@link com.mapbox.mapboxsdk.maps.TrackingSettings#setDismissLocationTrackingOnGesture(boolean)} with false before
+ * invoking this method and calling it with true in the {@link CancelableCallback#onFinish()}.
* </p>
*
* @param update The change that should be applied to the camera.
@@ -771,9 +842,12 @@ public final class MapboxMap {
* Do not update or ease the camera from within onCancel().
* @param isDismissable true will allow animated camera changes dismiss a tracking mode.
*/
- @UiThread
public final void easeCamera(final CameraUpdate update, final int durationMs, final boolean easingInterpolator,
final MapboxMap.CancelableCallback callback, final boolean isDismissable) {
+
+ if (durationMs <= 0) {
+ throw new IllegalArgumentException("Null duration passed into easeCamera");
+ }
new Handler().post(new Runnable() {
@Override
public void run() {
@@ -791,7 +865,6 @@ public final class MapboxMap {
* @param update The change that should be applied to the camera.
* @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
- @UiThread
public final void animateCamera(CameraUpdate update) {
animateCamera(update, MapboxConstants.ANIMATION_DURATION, null);
}
@@ -808,7 +881,6 @@ public final class MapboxMap {
* called. Do not update or animate the camera from within onCancel().
* @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
- @UiThread
public final void animateCamera(CameraUpdate update, MapboxMap.CancelableCallback callback) {
animateCamera(update, MapboxConstants.ANIMATION_DURATION, callback);
}
@@ -824,7 +896,6 @@ public final class MapboxMap {
* positive, otherwise an IllegalArgumentException will be thrown.
* @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
- @UiThread
public final void animateCamera(CameraUpdate update, int durationMs) {
animateCamera(update, durationMs, null);
}
@@ -847,9 +918,11 @@ public final class MapboxMap {
* isn't required, leave it as null.
* @see com.mapbox.mapboxsdk.camera.CameraUpdateFactory for a set of updates.
*/
- @UiThread
public final void animateCamera(final CameraUpdate update, final int durationMs,
final MapboxMap.CancelableCallback callback) {
+ if (durationMs <= 0) {
+ throw new IllegalArgumentException("Null duration passed into animageCamera");
+ }
new Handler().post(new Runnable() {
@Override
public void run() {
@@ -880,7 +953,12 @@ public final class MapboxMap {
}
/**
- * Set focal bearing.
+ * Transform the map bearing given a bearing, focal point coordinates, and a duration.
+ *
+ * @param bearing The bearing of the Map to be transformed to
+ * @param focalX The x coordinate of the focal point
+ * @param focalY The y coordinate of the focal point
+ * @param duration The duration of the transformation
*/
public void setFocalBearing(double bearing, float focalX, float focalY, long duration) {
transform.setBearing(bearing, focalX, focalY, duration);
@@ -913,7 +991,6 @@ public final class MapboxMap {
*
* @return If true, map debug information is currently shown.
*/
- @UiThread
public boolean isDebugActive() {
return nativeMapView.getDebug();
}
@@ -926,7 +1003,6 @@ public final class MapboxMap {
*
* @param debugActive If true, map debug information is shown.
*/
- @UiThread
public void setDebugActive(boolean debugActive) {
nativeMapView.setDebug(debugActive);
}
@@ -940,7 +1016,6 @@ public final class MapboxMap {
*
* @see #isDebugActive()
*/
- @UiThread
public void cycleDebugOptions() {
nativeMapView.cycleDebugOptions();
}
@@ -990,7 +1065,6 @@ public final class MapboxMap {
* @param url The URL of the map style
* @see Style
*/
- @UiThread
public void setStyleUrl(@NonNull String url) {
setStyleUrl(url, null);
}
@@ -1023,7 +1097,6 @@ public final class MapboxMap {
* @param callback The callback that is invoked when the style has loaded.
* @see Style
*/
- @UiThread
public void setStyleUrl(@NonNull final String url, @Nullable final OnStyleLoadedListener callback) {
if (callback != null) {
nativeMapView.addOnMapChangedListener(new MapView.OnMapChangedListener() {
@@ -1052,10 +1125,9 @@ public final class MapboxMap {
* An error message will be logged in the Android logcat and {@link MapView#DID_FAIL_LOADING_MAP} event will be
* sent.
*
- * @param style The bundled style. Accepts one of the values from {@link Style}.
+ * @param style The bundled style.
* @see Style
*/
- @UiThread
public void setStyle(@Style.StyleUrl String style) {
setStyleUrl(style);
}
@@ -1068,10 +1140,10 @@ public final class MapboxMap {
* An error message will be logged in the Android logcat and {@link MapView#DID_FAIL_LOADING_MAP} event will be
* sent.
*
- * @param style The bundled style. Accepts one of the values from {@link Style}.
+ * @param style The bundled style.
+ * @param callback The callback to be invoked when the style has finished loading
* @see Style
*/
- @UiThread
public void setStyle(@Style.StyleUrl String style, @Nullable OnStyleLoadedListener callback) {
setStyleUrl(style, callback);
}
@@ -1089,16 +1161,36 @@ public final class MapboxMap {
}
/**
- * Returns the map style currently displayed in the map view.
+ * Returns the map style url currently displayed in the map view.
*
* @return The URL of the map style
*/
- @UiThread
@Nullable
public String getStyleUrl() {
return nativeMapView.getStyleUrl();
}
+ /**
+ * Loads a new map style from a json string.
+ * <p>
+ * If the style fails to load or an invalid style URL is set, the map view will become blank.
+ * An error message will be logged in the Android logcat and {@link MapView#DID_FAIL_LOADING_MAP} event will be
+ * sent.
+ * </p>
+ */
+ public void setStyleJson(@NonNull String styleJson) {
+ nativeMapView.setStyleJson(styleJson);
+ }
+
+ /**
+ * Returns the map style json currently displayed in the map view.
+ *
+ * @return The json of the map style
+ */
+ public String getStyleJson() {
+ return nativeMapView.getStyleJson();
+ }
+
//
// Annotations
//
@@ -1113,7 +1205,6 @@ public final class MapboxMap {
* @param markerOptions A marker options object that defines how to render the marker
* @return The {@code Marker} that was added to the map
*/
- @UiThread
@NonNull
public Marker addMarker(@NonNull MarkerOptions markerOptions) {
return annotationManager.addMarker(markerOptions, this);
@@ -1129,7 +1220,6 @@ public final class MapboxMap {
* @param markerOptions A marker options object that defines how to render the marker
* @return The {@code Marker} that was added to the map
*/
- @UiThread
@NonNull
public Marker addMarker(@NonNull BaseMarkerOptions markerOptions) {
return annotationManager.addMarker(markerOptions, this);
@@ -1144,9 +1234,11 @@ public final class MapboxMap {
*
* @param markerOptions A marker options object that defines how to render the marker
* @return The {@code Marker} that was added to the map
+ * @deprecated Use a {@link com.mapbox.mapboxsdk.style.layers.SymbolLayer} instead. An example of converting Android
+ * SDK views to be used as a symbol see https://github.com/mapbox/mapbox-gl-native/blob/68f32bc104422207c64da8d90e8411b138d87f04/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java
*/
- @UiThread
@NonNull
+ @Deprecated
public MarkerView addMarker(@NonNull BaseMarkerViewOptions markerOptions) {
return annotationManager.addMarker(markerOptions, this, null);
}
@@ -1161,8 +1253,10 @@ public final class MapboxMap {
* @param markerOptions A marker options object that defines how to render the marker
* @param onMarkerViewAddedListener Callback invoked when the View has been added to the map
* @return The {@code Marker} that was added to the map
+ * @deprecated Use a {@link com.mapbox.mapboxsdk.style.layers.SymbolLayer} instead. An example of converting Android
+ * SDK views to be used as a symbol see https://github.com/mapbox/mapbox-gl-native/blob/68f32bc104422207c64da8d90e8411b138d87f04/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java
*/
- @UiThread
+ @Deprecated
@NonNull
public MarkerView addMarker(@NonNull BaseMarkerViewOptions markerOptions,
final MarkerViewManager.OnMarkerViewAddedListener onMarkerViewAddedListener) {
@@ -1178,9 +1272,11 @@ public final class MapboxMap {
*
* @param markerViewOptions A list of markerView options objects that defines how to render the markers
* @return A list of the {@code MarkerView}s that were added to the map
+ * @deprecated Use a {@link com.mapbox.mapboxsdk.style.layers.SymbolLayer} instead. An example of converting Android
+ * SDK views to be used as a symbol see https://github.com/mapbox/mapbox-gl-native/blob/68f32bc104422207c64da8d90e8411b138d87f04/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java
*/
- @UiThread
@NonNull
+ @Deprecated
public List<MarkerView> addMarkerViews(@NonNull List<? extends
BaseMarkerViewOptions> markerViewOptions) {
return annotationManager.addMarkerViews(markerViewOptions, this);
@@ -1191,9 +1287,11 @@ public final class MapboxMap {
*
* @param rect the rectangular area on the map to query for markerViews
* @return A list of the markerViews that were found in the rectangle
+ * @deprecated Use a {@link com.mapbox.mapboxsdk.style.layers.SymbolLayer} instead. An example of converting Android
+ * SDK views to be used as a symbol see https://github.com/mapbox/mapbox-gl-native/blob/68f32bc104422207c64da8d90e8411b138d87f04/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java
*/
- @UiThread
@NonNull
+ @Deprecated
public List<MarkerView> getMarkerViewsInRect(@NonNull RectF rect) {
return annotationManager.getMarkerViewsInRect(rect);
}
@@ -1208,7 +1306,6 @@ public final class MapboxMap {
* @param markerOptionsList A list of marker options objects that defines how to render the markers
* @return A list of the {@code Marker}s that were added to the map
*/
- @UiThread
@NonNull
public List<Marker> addMarkers(@NonNull List<? extends
BaseMarkerOptions> markerOptionsList) {
@@ -1222,7 +1319,6 @@ public final class MapboxMap {
*
* @param updatedMarker An updated marker object
*/
- @UiThread
public void updateMarker(@NonNull Marker updatedMarker) {
annotationManager.updateMarker(updatedMarker, this);
}
@@ -1233,7 +1329,6 @@ public final class MapboxMap {
* @param polylineOptions A polyline options object that defines how to render the polyline
* @return The {@code Polyine} that was added to the map
*/
- @UiThread
@NonNull
public Polyline addPolyline(@NonNull PolylineOptions polylineOptions) {
return annotationManager.addPolyline(polylineOptions, this);
@@ -1245,7 +1340,6 @@ public final class MapboxMap {
* @param polylineOptionsList A list of polyline options objects that defines how to render the polylines.
* @return A list of the {@code Polyline}s that were added to the map.
*/
- @UiThread
@NonNull
public List<Polyline> addPolylines(@NonNull List<PolylineOptions> polylineOptionsList) {
return annotationManager.addPolylines(polylineOptionsList, this);
@@ -1256,7 +1350,6 @@ public final class MapboxMap {
*
* @param polyline An updated polyline object.
*/
- @UiThread
public void updatePolyline(Polyline polyline) {
annotationManager.updatePolyline(polyline);
}
@@ -1267,7 +1360,6 @@ public final class MapboxMap {
* @param polygonOptions A polygon options object that defines how to render the polygon.
* @return The {@code Polygon} that was added to the map.
*/
- @UiThread
@NonNull
public Polygon addPolygon(@NonNull PolygonOptions polygonOptions) {
return annotationManager.addPolygon(polygonOptions, this);
@@ -1279,7 +1371,6 @@ public final class MapboxMap {
* @param polygonOptionsList A list of polygon options objects that defines how to render the polygons
* @return A list of the {@code Polygon}s that were added to the map
*/
- @UiThread
@NonNull
public List<Polygon> addPolygons(@NonNull List<PolygonOptions> polygonOptionsList) {
return annotationManager.addPolygons(polygonOptionsList, this);
@@ -1290,7 +1381,6 @@ public final class MapboxMap {
*
* @param polygon An updated polygon object
*/
- @UiThread
public void updatePolygon(Polygon polygon) {
annotationManager.updatePolygon(polygon);
}
@@ -1303,7 +1393,6 @@ public final class MapboxMap {
*
* @param marker Marker to remove
*/
- @UiThread
public void removeMarker(@NonNull Marker marker) {
annotationManager.removeAnnotation(marker);
}
@@ -1316,7 +1405,6 @@ public final class MapboxMap {
*
* @param polyline Polyline to remove
*/
- @UiThread
public void removePolyline(@NonNull Polyline polyline) {
annotationManager.removeAnnotation(polyline);
}
@@ -1329,7 +1417,6 @@ public final class MapboxMap {
*
* @param polygon Polygon to remove
*/
- @UiThread
public void removePolygon(@NonNull Polygon polygon) {
annotationManager.removeAnnotation(polygon);
}
@@ -1339,7 +1426,6 @@ public final class MapboxMap {
*
* @param annotation The annotation object to remove.
*/
- @UiThread
public void removeAnnotation(@NonNull Annotation annotation) {
annotationManager.removeAnnotation(annotation);
}
@@ -1349,7 +1435,6 @@ public final class MapboxMap {
*
* @param id The identifier associated to the annotation to be removed
*/
- @UiThread
public void removeAnnotation(long id) {
annotationManager.removeAnnotation(id);
}
@@ -1359,7 +1444,6 @@ public final class MapboxMap {
*
* @param annotationList A list of annotation objects to remove.
*/
- @UiThread
public void removeAnnotations(@NonNull List<? extends Annotation> annotationList) {
annotationManager.removeAnnotations(annotationList);
}
@@ -1367,7 +1451,6 @@ public final class MapboxMap {
/**
* Removes all annotations from the map.
*/
- @UiThread
public void removeAnnotations() {
annotationManager.removeAnnotations();
}
@@ -1375,7 +1458,6 @@ public final class MapboxMap {
/**
* Removes all markers, polylines, polygons, overlays, etc from the map.
*/
- @UiThread
public void clear() {
annotationManager.removeAnnotations();
}
@@ -1441,12 +1523,31 @@ public final class MapboxMap {
* @param listener The callback that's invoked when the user clicks on a marker.
* To unset the callback, use null.
*/
- @UiThread
public void setOnMarkerClickListener(@Nullable OnMarkerClickListener listener) {
annotationManager.setOnMarkerClickListener(listener);
}
/**
+ * Sets a callback that's invoked when the user clicks on a polygon.
+ *
+ * @param listener The callback that's invoked when the user clicks on a polygon.
+ * To unset the callback, use null.
+ */
+ public void setOnPolygonClickListener(@Nullable OnPolygonClickListener listener) {
+ annotationManager.setOnPolygonClickListener(listener);
+ }
+
+ /**
+ * Sets a callback that's invoked when the user clicks on a polyline.
+ *
+ * @param listener The callback that's invoked when the user clicks on a polyline.
+ * To unset the callback, use null.
+ */
+ public void setOnPolylineClickListener(@Nullable OnPolylineClickListener listener) {
+ annotationManager.setOnPolylineClickListener(listener);
+ }
+
+ /**
* <p>
* Selects a marker. The selected marker will have it's info window opened.
* Any other open info windows will be closed unless isAllowConcurrentMultipleOpenInfoWindows()
@@ -1456,7 +1557,6 @@ public final class MapboxMap {
*
* @param marker The marker to select.
*/
- @UiThread
public void selectMarker(@NonNull Marker marker) {
if (marker == null) {
Timber.w("marker was null, so just returning");
@@ -1468,7 +1568,6 @@ public final class MapboxMap {
/**
* Deselects any currently selected marker. All markers will have it's info window closed.
*/
- @UiThread
public void deselectMarkers() {
annotationManager.deselectMarkers();
}
@@ -1478,7 +1577,6 @@ public final class MapboxMap {
*
* @param marker the marker to deselect
*/
- @UiThread
public void deselectMarker(@NonNull Marker marker) {
annotationManager.deselectMarker(marker);
}
@@ -1488,7 +1586,6 @@ public final class MapboxMap {
*
* @return The currently selected marker.
*/
- @UiThread
public List<Marker> getSelectedMarkers() {
return annotationManager.getSelectedMarkers();
}
@@ -1516,7 +1613,6 @@ public final class MapboxMap {
* @param infoWindowAdapter The callback to be invoked when an info window will be shown.
* To unset the callback, use null.
*/
- @UiThread
public void setInfoWindowAdapter(@Nullable InfoWindowAdapter infoWindowAdapter) {
annotationManager.getInfoWindowManager().setInfoWindowAdapter(infoWindowAdapter);
}
@@ -1526,7 +1622,6 @@ public final class MapboxMap {
*
* @return The callback to be invoked when an info window will be shown.
*/
- @UiThread
@Nullable
public InfoWindowAdapter getInfoWindowAdapter() {
return annotationManager.getInfoWindowManager().getInfoWindowAdapter();
@@ -1537,7 +1632,6 @@ public final class MapboxMap {
*
* @param allow If true, map allows concurrent multiple infowindows to be shown.
*/
- @UiThread
public void setAllowConcurrentMultipleOpenInfoWindows(boolean allow) {
annotationManager.getInfoWindowManager().setAllowConcurrentMultipleOpenInfoWindows(allow);
}
@@ -1547,7 +1641,6 @@ public final class MapboxMap {
*
* @return If true, map allows concurrent multiple infowindows to be shown.
*/
- @UiThread
public boolean isAllowConcurrentMultipleOpenInfoWindows() {
return annotationManager.getInfoWindowManager().isAllowConcurrentMultipleOpenInfoWindows();
}
@@ -1569,9 +1662,11 @@ public final class MapboxMap {
}
/**
- * Gets a camera position that would fit a bounds.
+ * Get a camera position that fits a provided bounds and padding.
*
* @param latLngBounds the bounds to constrain the map with
+ * @param padding the padding to apply to the bounds
+ * @return the camera position that fits the bounds and padding
*/
public CameraPosition getCameraForLatLngBounds(@Nullable LatLngBounds latLngBounds, int[] padding) {
// calculate and set additional bounds padding
@@ -1589,6 +1684,30 @@ public final class MapboxMap {
return cameraPosition;
}
+ /**
+ * Get a camera position that fits a provided shape with a given bearing and padding.
+ *
+ * @param geometry the geometry to constrain the map with
+ * @param bearing the bearing at which to compute the geometry's bounds
+ * @param padding the padding to apply to the bounds
+ * @return the camera position that fits the bounds and padding
+ */
+ public CameraPosition getCameraForGeometry(Geometry geometry, double bearing, int[] padding) {
+ // calculate and set additional bounds padding
+ int[] mapPadding = getPadding();
+ for (int i = 0; i < padding.length; i++) {
+ padding[i] = mapPadding[i] + padding[i];
+ }
+ projection.setContentPadding(padding, myLocationViewSettings.getPadding());
+
+ // get padded camera position from LatLngBounds
+ CameraPosition cameraPosition = nativeMapView.getCameraForGeometry(geometry, bearing);
+
+ // reset map padding
+ setPadding(mapPadding);
+ return cameraPosition;
+ }
+
//
// Padding
//
@@ -1639,7 +1758,6 @@ public final class MapboxMap {
* @param listener The callback that's invoked on every camera change position.
* To unset the callback, use null.
*/
- @UiThread
@Deprecated
public void setOnCameraChangeListener(@Nullable OnCameraChangeListener listener) {
transform.setOnCameraChangeListener(listener);
@@ -1649,51 +1767,131 @@ public final class MapboxMap {
* Sets a callback that is invoked when camera movement has ended.
*
* @param listener the listener to notify
+ * @deprecated use {@link #addOnCameraIdleListener(OnCameraIdleListener)}
+ * and {@link #removeOnCameraIdleListener(OnCameraIdleListener)} instead
*/
- @UiThread
+ @Deprecated
public void setOnCameraIdleListener(@Nullable OnCameraIdleListener listener) {
cameraChangeDispatcher.setOnCameraIdleListener(listener);
}
/**
+ * Adds a callback that is invoked when camera movement has ended.
+ *
+ * @param listener the listener to notify
+ */
+ public void addOnCameraIdleListener(@Nullable OnCameraIdleListener listener) {
+ cameraChangeDispatcher.addOnCameraIdleListener(listener);
+ }
+
+ /**
+ * Removes a callback that is invoked when camera movement has ended.
+ *
+ * @param listener the listener to remove
+ */
+ public void removeOnCameraIdleListener(@Nullable OnCameraIdleListener listener) {
+ cameraChangeDispatcher.removeOnCameraIdleListener(listener);
+ }
+
+ /**
* Sets a callback that is invoked when camera movement was cancelled.
*
* @param listener the listener to notify
+ * @deprecated use {@link #addOnCameraMoveCancelListener(OnCameraMoveCanceledListener)} and
+ * {@link #removeOnCameraMoveCancelListener(OnCameraMoveCanceledListener)} instead
*/
- @UiThread
+ @Deprecated
public void setOnCameraMoveCancelListener(@Nullable OnCameraMoveCanceledListener listener) {
cameraChangeDispatcher.setOnCameraMoveCanceledListener(listener);
}
/**
+ * Adds a callback that is invoked when camera movement was cancelled.
+ *
+ * @param listener the listener to notify
+ */
+ public void addOnCameraMoveCancelListener(@Nullable OnCameraMoveCanceledListener listener) {
+ cameraChangeDispatcher.addOnCameraMoveCancelListener(listener);
+ }
+
+ /**
+ * Removes a callback that is invoked when camera movement was cancelled.
+ *
+ * @param listener the listener to remove
+ */
+ public void removeOnCameraMoveCancelListener(@Nullable OnCameraMoveCanceledListener listener) {
+ cameraChangeDispatcher.removeOnCameraMoveCancelListener(listener);
+ }
+
+ /**
* Sets a callback that is invoked when camera movement has started.
*
* @param listener the listener to notify
+ * @deprecated use {@link #addOnCameraMoveStartedListener(OnCameraMoveStartedListener)} and
+ * {@link #removeOnCameraMoveStartedListener(OnCameraMoveStartedListener)} instead
*/
- @UiThread
- public void setOnCameraMoveStartedistener(@Nullable OnCameraMoveStartedListener listener) {
+ @Deprecated
+ public void setOnCameraMoveStartedListener(@Nullable OnCameraMoveStartedListener listener) {
cameraChangeDispatcher.setOnCameraMoveStartedListener(listener);
}
/**
+ * Adds a callback that is invoked when camera movement has started.
+ *
+ * @param listener the listener to notify
+ */
+ public void addOnCameraMoveStartedListener(@Nullable OnCameraMoveStartedListener listener) {
+ cameraChangeDispatcher.addOnCameraMoveStartedListener(listener);
+ }
+
+ /**
+ * Removes a callback that is invoked when camera movement has started.
+ *
+ * @param listener the listener to remove
+ */
+ public void removeOnCameraMoveStartedListener(@Nullable OnCameraMoveStartedListener listener) {
+ cameraChangeDispatcher.removeOnCameraMoveStartedListener(listener);
+ }
+
+ /**
* Sets a callback that is invoked when camera position changes.
*
* @param listener the listener to notify
+ * @deprecated use {@link #addOnCameraMoveListener(OnCameraMoveListener)} and
+ * {@link #removeOnCameraMoveListener(OnCameraMoveListener)}instead
*/
- @UiThread
+ @Deprecated
public void setOnCameraMoveListener(@Nullable OnCameraMoveListener listener) {
cameraChangeDispatcher.setOnCameraMoveListener(listener);
}
/**
+ * Adds a callback that is invoked when camera position changes.
+ *
+ * @param listener the listener to notify
+ */
+ public void addOnCameraMoveListener(@Nullable OnCameraMoveListener listener) {
+ cameraChangeDispatcher.addOnCameraMoveListener(listener);
+ }
+
+ /**
+ * Removes a callback that is invoked when camera position changes.
+ *
+ * @param listener the listener to remove
+ */
+ public void removeOnCameraMoveListener(@Nullable OnCameraMoveListener listener) {
+ cameraChangeDispatcher.removeOnCameraMoveListener(listener);
+ }
+
+ /**
* Sets a callback that's invoked on every frame rendered to the map view.
*
* @param listener The callback that's invoked on every frame rendered to the map view.
* To unset the callback, use null.
*/
- @UiThread
public void setOnFpsChangedListener(@Nullable OnFpsChangedListener listener) {
onFpsChangedListener = listener;
+ nativeMapView.setOnFpsChangedListener(listener);
}
// used by MapView
@@ -1706,10 +1904,34 @@ public final class MapboxMap {
*
* @param listener The callback that's invoked when the map is scrolled.
* To unset the callback, use null.
+ *
+ * @deprecated Use {@link #addOnScrollListener(OnScrollListener)} instead.
*/
- @UiThread
+ @Deprecated
public void setOnScrollListener(@Nullable OnScrollListener listener) {
- onRegisterTouchListener.onRegisterScrollListener(listener);
+ onRegisterTouchListener.onSetScrollListener(listener);
+ }
+
+ /**
+ * Adds a callback that's invoked when the map is scrolled.
+ *
+ * @param listener The callback that's invoked when the map is scrolled.
+ * To unset the callback, use null.
+ *
+ */
+ public void addOnScrollListener(@Nullable OnScrollListener listener) {
+ onRegisterTouchListener.onAddScrollListener(listener);
+ }
+
+ /**
+ * Removes a callback that's invoked when the map is scrolled.
+ *
+ * @param listener The callback that's invoked when the map is scrolled.
+ * To unset the callback, use null.
+ *
+ */
+ public void removeOnScrollListener(@Nullable OnScrollListener listener) {
+ onRegisterTouchListener.onRemoveScrollListener(listener);
}
/**
@@ -1717,10 +1939,32 @@ public final class MapboxMap {
*
* @param listener The callback that's invoked when the map is flinged.
* To unset the callback, use null.
+ *
+ * @deprecated Use {@link #addOnFlingListener(OnFlingListener)} instead.
*/
- @UiThread
+ @Deprecated
public void setOnFlingListener(@Nullable OnFlingListener listener) {
- onRegisterTouchListener.onRegisterFlingListener(listener);
+ onRegisterTouchListener.onSetFlingListener(listener);
+ }
+
+ /**
+ * Adds a callback that's invoked when the map is flinged.
+ *
+ * @param listener The callback that's invoked when the map is flinged.
+ * To unset the callback, use null.
+ */
+ public void addOnFlingListener(@Nullable OnFlingListener listener) {
+ onRegisterTouchListener.onAddFlingListener(listener);
+ }
+
+ /**
+ * Removes a callback that's invoked when the map is flinged.
+ *
+ * @param listener The callback that's invoked when the map is flinged.
+ * To unset the callback, use null.
+ */
+ public void removeOnFlingListener(@Nullable OnFlingListener listener) {
+ onRegisterTouchListener.onRemoveFlingListener(listener);
}
/**
@@ -1728,10 +1972,32 @@ public final class MapboxMap {
*
* @param listener The callback that's invoked when the user clicks on the map view.
* To unset the callback, use null.
+ *
+ * @deprecated Use {@link #addOnMapClickListener(OnMapClickListener)} instead.
*/
- @UiThread
+ @Deprecated
public void setOnMapClickListener(@Nullable OnMapClickListener listener) {
- onRegisterTouchListener.onRegisterMapClickListener(listener);
+ onRegisterTouchListener.onSetMapClickListener(listener);
+ }
+
+ /**
+ * Adds a callback that's invoked when the user clicks on the map view.
+ *
+ * @param listener The callback that's invoked when the user clicks on the map view.
+ * To unset the callback, use null.
+ */
+ public void addOnMapClickListener(@Nullable OnMapClickListener listener) {
+ onRegisterTouchListener.onAddMapClickListener(listener);
+ }
+
+ /**
+ * Removes a callback that's invoked when the user clicks on the map view.
+ *
+ * @param listener The callback that's invoked when the user clicks on the map view.
+ * To unset the callback, use null.
+ */
+ public void removeOnMapClickListener(@Nullable OnMapClickListener listener) {
+ onRegisterTouchListener.onRemoveMapClickListener(listener);
}
/**
@@ -1739,10 +2005,32 @@ public final class MapboxMap {
*
* @param listener The callback that's invoked when the user long clicks on the map view.
* To unset the callback, use null.
+ *
+ * @deprecated Use {@link #addOnMapLongClickListener(OnMapLongClickListener)} instead.
*/
- @UiThread
+ @Deprecated
public void setOnMapLongClickListener(@Nullable OnMapLongClickListener listener) {
- onRegisterTouchListener.onRegisterMapLongClickListener(listener);
+ onRegisterTouchListener.onSetMapLongClickListener(listener);
+ }
+
+ /**
+ * Adds a callback that's invoked when the user long clicks on the map view.
+ *
+ * @param listener The callback that's invoked when the user long clicks on the map view.
+ * To unset the callback, use null.
+ */
+ public void addOnMapLongClickListener(@Nullable OnMapLongClickListener listener) {
+ onRegisterTouchListener.onAddMapLongClickListener(listener);
+ }
+
+ /**
+ * Removes a callback that's invoked when the user long clicks on the map view.
+ *
+ * @param listener The callback that's invoked when the user long clicks on the map view.
+ * To unset the callback, use null.
+ */
+ public void removeOnMapLongClickListener(@Nullable OnMapLongClickListener listener) {
+ onRegisterTouchListener.onRemoveMapLongClickListener(listener);
}
/**
@@ -1751,7 +2039,6 @@ public final class MapboxMap {
* @param listener The callback that's invoked when the user clicks on an info window.
* To unset the callback, use null.
*/
- @UiThread
public void setOnInfoWindowClickListener(@Nullable OnInfoWindowClickListener listener) {
annotationManager.getInfoWindowManager().setOnInfoWindowClickListener(listener);
}
@@ -1761,7 +2048,6 @@ public final class MapboxMap {
*
* @return Current active InfoWindow Click Listener
*/
- @UiThread
public OnInfoWindowClickListener getOnInfoWindowClickListener() {
return annotationManager.getInfoWindowManager().getOnInfoWindowClickListener();
}
@@ -1772,7 +2058,6 @@ public final class MapboxMap {
* @param listener The callback that's invoked when a marker's info window is long pressed. To unset the callback,
* use null.
*/
- @UiThread
public void setOnInfoWindowLongClickListener(@Nullable OnInfoWindowLongClickListener
listener) {
annotationManager.getInfoWindowManager().setOnInfoWindowLongClickListener(listener);
@@ -1801,7 +2086,6 @@ public final class MapboxMap {
*
* @return Current active InfoWindow Close Listener
*/
- @UiThread
public OnInfoWindowCloseListener getOnInfoWindowCloseListener() {
return annotationManager.getInfoWindowManager().getOnInfoWindowCloseListener();
}
@@ -1814,8 +2098,10 @@ public final class MapboxMap {
* Returns the status of the my-location layer.
*
* @return True if the my-location layer is enabled, false otherwise.
+ * @deprecated use location layer plugin from
+ * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugin-locationlayer instead.
*/
- @UiThread
+ @Deprecated
public boolean isMyLocationEnabled() {
return trackingSettings.isMyLocationEnabled();
}
@@ -1830,8 +2116,10 @@ public final class MapboxMap {
* android.Manifest.permission#ACCESS_COARSE_LOCATION or android.Manifest.permission#ACCESS_FINE_LOCATION.
*
* @param enabled True to enable; false to disable.
+ * @deprecated use location layer plugin from
+ * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugin-locationlayer instead.
*/
- @UiThread
+ @Deprecated
public void setMyLocationEnabled(boolean enabled) {
trackingSettings.setMyLocationEnabled(enabled);
}
@@ -1840,9 +2128,11 @@ public final class MapboxMap {
* Returns the currently displayed user location, or null if there is no location data available.
*
* @return The currently displayed user location.
+ * @deprecated use location layer plugin from
+ * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugin-locationlayer instead.
*/
- @UiThread
@Nullable
+ @Deprecated
public Location getMyLocation() {
return trackingSettings.getMyLocation();
}
@@ -1853,8 +2143,10 @@ public final class MapboxMap {
*
* @param listener The callback that's invoked when the user clicks on a marker.
* To unset the callback, use null.
+ * @deprecated use location layer plugin from
+ * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugin-locationlayer instead.
*/
- @UiThread
+ @Deprecated
public void setOnMyLocationChangeListener(@Nullable MapboxMap.OnMyLocationChangeListener
listener) {
trackingSettings.setOnMyLocationChangeListener(listener);
@@ -1864,10 +2156,10 @@ public final class MapboxMap {
* Replaces the location source of the my-location layer.
*
* @param locationSource A {@link LocationEngine} location source to use in the my-location layer.
- * Set to null to use the default {@link LocationSource}
- * location source.
+ * @deprecated use location layer plugin from
+ * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugin-locationlayer instead.
*/
- @UiThread
+ @Deprecated
public void setLocationSource(@Nullable LocationEngine locationSource) {
trackingSettings.setLocationSource(locationSource);
}
@@ -1877,8 +2169,10 @@ public final class MapboxMap {
*
* @param listener The callback that's invoked when the location tracking mode changes.
* To unset the callback, use null.
+ * @deprecated use location layer plugin from
+ * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugin-locationlayer instead.
*/
- @UiThread
+ @Deprecated
public void setOnMyLocationTrackingModeChangeListener(
@Nullable MapboxMap.OnMyLocationTrackingModeChangeListener listener) {
trackingSettings.setOnMyLocationTrackingModeChangeListener(listener);
@@ -1889,8 +2183,10 @@ public final class MapboxMap {
*
* @param listener The callback that's invoked when the bearing tracking mode changes.
* To unset the callback, use null.
+ * @deprecated use location layer plugin from
+ * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugin-locationlayer instead.
*/
- @UiThread
+ @Deprecated
public void setOnMyBearingTrackingModeChangeListener(@Nullable OnMyBearingTrackingModeChangeListener listener) {
trackingSettings.setOnMyBearingTrackingModeChangeListener(listener);
}
@@ -1904,7 +2200,6 @@ public final class MapboxMap {
*
* @param callback Callback method invoked when the snapshot is taken.
*/
- @UiThread
public void snapshot(@NonNull SnapshotReadyCallback callback) {
nativeMapView.addSnapshotCallback(callback);
}
@@ -1916,7 +2211,6 @@ public final class MapboxMap {
* @param layerIds optionally - only query these layers
* @return the list of feature
*/
- @UiThread
@NonNull
public List<Feature> queryRenderedFeatures(@NonNull PointF coordinates, @Nullable String...
layerIds) {
@@ -1931,7 +2225,6 @@ public final class MapboxMap {
* @param layerIds optionally - only query these layers
* @return the list of feature
*/
- @UiThread
@NonNull
public List<Feature> queryRenderedFeatures(@NonNull PointF coordinates,
@Nullable Filter.Statement filter,
@@ -1946,7 +2239,6 @@ public final class MapboxMap {
* @param layerIds optionally - only query these layers
* @return the list of feature
*/
- @UiThread
@NonNull
public List<Feature> queryRenderedFeatures(@NonNull RectF coordinates,
@Nullable String... layerIds) {
@@ -1961,7 +2253,6 @@ public final class MapboxMap {
* @param layerIds optionally - only query these layers
* @return the list of feature
*/
- @UiThread
@NonNull
public List<Feature> queryRenderedFeatures(@NonNull RectF coordinates,
@Nullable Filter.Statement filter,
@@ -1969,6 +2260,15 @@ public final class MapboxMap {
return nativeMapView.queryRenderedFeatures(coordinates, layerIds, filter);
}
+ FocalPointChangeListener createFocalPointChangeListener() {
+ return new FocalPointChangeListener() {
+ @Override
+ public void onFocalPointChanged(PointF pointF) {
+ focalPoint = pointF;
+ }
+ };
+ }
+
//
// Interfaces
//
@@ -2067,6 +2367,21 @@ public final class MapboxMap {
}
/**
+ * Interface definition for a callback to be invoked for when the compass is animating.
+ */
+ public interface OnCompassAnimationListener {
+ /**
+ * Called repeatedly as the compass continues to move after clicking on it.
+ */
+ void onCompassAnimation();
+
+ /**
+ * Called when compass animation has ended.
+ */
+ void onCompassAnimationFinished();
+ }
+
+ /**
* Interface definition for a callback to be invoked when a frame is rendered to the map view.
*
* @see MapboxMap#setOnFpsChangedListener(OnFpsChangedListener)
@@ -2085,13 +2400,29 @@ public final class MapboxMap {
* related to touch and click events.
*/
interface OnRegisterTouchListener {
- void onRegisterMapClickListener(OnMapClickListener listener);
+ void onSetMapClickListener(OnMapClickListener listener);
+
+ void onAddMapClickListener(OnMapClickListener listener);
+
+ void onRemoveMapClickListener(OnMapClickListener listener);
- void onRegisterMapLongClickListener(OnMapLongClickListener listener);
+ void onSetMapLongClickListener(OnMapLongClickListener listener);
- void onRegisterScrollListener(OnScrollListener listener);
+ void onAddMapLongClickListener(OnMapLongClickListener listener);
- void onRegisterFlingListener(OnFlingListener listener);
+ void onRemoveMapLongClickListener(OnMapLongClickListener listener);
+
+ void onSetScrollListener(OnScrollListener listener);
+
+ void onAddScrollListener(OnScrollListener listener);
+
+ void onRemoveScrollListener(OnScrollListener listener);
+
+ void onSetFlingListener(OnFlingListener listener);
+
+ void onAddFlingListener(OnFlingListener listener);
+
+ void onRemoveFlingListener(OnFlingListener listener);
}
/**
@@ -2138,6 +2469,34 @@ public final class MapboxMap {
}
/**
+ * Interface definition for a callback to be invoked when the user clicks on a polygon.
+ *
+ * @see MapboxMap#setOnPolygonClickListener(OnPolygonClickListener)
+ */
+ public interface OnPolygonClickListener {
+ /**
+ * Called when the user clicks on a polygon.
+ *
+ * @param polygon The polygon the user clicked on.
+ */
+ void onPolygonClick(@NonNull Polygon polygon);
+ }
+
+ /**
+ * Interface definition for a callback to be invoked when the user clicks on a polyline.
+ *
+ * @see MapboxMap#setOnPolylineClickListener(OnPolylineClickListener)
+ */
+ public interface OnPolylineClickListener {
+ /**
+ * Called when the user clicks on a polyline.
+ *
+ * @param polyline The polyline the user clicked on.
+ */
+ void onPolylineClick(@NonNull Polyline polyline);
+ }
+
+ /**
* Interface definition for a callback to be invoked when the user clicks on an info window.
*
* @see MapboxMap#setOnInfoWindowClickListener(OnInfoWindowClickListener)
@@ -2203,7 +2562,10 @@ public final class MapboxMap {
* Interface definition for a callback to be invoked when an MarkerView will be shown.
*
* @param <U> the instance type of MarkerView
+ * @deprecated Use a {@link com.mapbox.mapboxsdk.style.layers.SymbolLayer} instead. An example of converting Android
+ * SDK views to be used as a symbol see https://github.com/mapbox/mapbox-gl-native/blob/68f32bc104422207c64da8d90e8411b138d87f04/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolGeneratorActivity.java
*/
+ @Deprecated
public abstract static class MarkerViewAdapter<U extends MarkerView> {
private Context context;
@@ -2405,11 +2767,13 @@ public final class MapboxMap {
}
/**
- * Interface definintion for a callback to be invoked when the style has finished loading.
+ * Interface definition for a callback to be invoked when the style has finished loading.
*/
public interface OnStyleLoadedListener {
/**
- * Invoked when the style has finished loading.
+ * Invoked when the style has finished loading
+ *
+ * @param style the style that has been loaded
*/
void onStyleLoaded(String style);
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java
index 98f94ddb39..2719d7f016 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java
@@ -3,8 +3,6 @@ package com.mapbox.mapboxsdk.maps;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
@@ -21,6 +19,7 @@ import android.view.Gravity;
import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
+import com.mapbox.mapboxsdk.utils.BitmapUtils;
import com.mapbox.mapboxsdk.utils.ColorUtils;
import java.util.Arrays;
@@ -37,6 +36,7 @@ public class MapboxMapOptions implements Parcelable {
private static final float FOUR_DP = 4f;
private static final float NINETY_TWO_DP = 92f;
+ private static final int UNDEFINED_COLOR = -1;
private CameraPosition cameraPosition;
@@ -53,7 +53,7 @@ public class MapboxMapOptions implements Parcelable {
private int[] logoMargins;
@ColorInt
- private int attributionTintColor = -1;
+ private int attributionTintColor = UNDEFINED_COLOR;
private boolean attributionEnabled = true;
private int attributionGravity = Gravity.BOTTOM;
private int[] attributionMargins;
@@ -72,15 +72,20 @@ public class MapboxMapOptions implements Parcelable {
private Drawable myLocationForegroundDrawable;
private Drawable myLocationForegroundBearingDrawable;
private Drawable myLocationBackgroundDrawable;
- private int myLocationForegroundTintColor;
- private int myLocationBackgroundTintColor;
+ @ColorInt
+ private int myLocationForegroundTintColor = UNDEFINED_COLOR;
+ @ColorInt
+ private int myLocationBackgroundTintColor = UNDEFINED_COLOR;
private int[] myLocationBackgroundPadding;
private int myLocationAccuracyTintColor;
private int myLocationAccuracyAlpha;
+ private float myLocationAccuracyThreshold;
+ private boolean prefetchesTiles = true;
+ private boolean zMediaOverlay = false;
+ private String localIdeographFontFamily;
private String apiBaseUrl;
- @Deprecated
private boolean textureMode;
private String style;
@@ -146,23 +151,14 @@ public class MapboxMapOptions implements Parcelable {
myLocationBackgroundPadding = in.createIntArray();
myLocationAccuracyAlpha = in.readInt();
myLocationAccuracyTintColor = in.readInt();
+ myLocationAccuracyThreshold = in.readFloat();
style = in.readString();
apiBaseUrl = in.readString();
textureMode = in.readByte() != 0;
- }
-
- static Bitmap getBitmapFromDrawable(Drawable drawable) {
- if (drawable instanceof BitmapDrawable) {
- return ((BitmapDrawable) drawable).getBitmap();
- } else {
- Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(),
- Bitmap.Config.ARGB_8888);
- Canvas canvas = new Canvas(bitmap);
- drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
- drawable.draw(canvas);
- return bitmap;
- }
+ prefetchesTiles = in.readByte() != 0;
+ zMediaOverlay = in.readByte() != 0;
+ localIdeographFontFamily = in.readString();
}
/**
@@ -234,7 +230,7 @@ public class MapboxMapOptions implements Parcelable {
FOUR_DP * pxlRatio))});
mapboxMapOptions.attributionTintColor(typedArray.getColor(
- R.styleable.mapbox_MapView_mapbox_uiAttributionTintColor, -1));
+ R.styleable.mapbox_MapView_mapbox_uiAttributionTintColor, UNDEFINED_COLOR));
mapboxMapOptions.attributionEnabled(typedArray.getBoolean(
R.styleable.mapbox_MapView_mapbox_uiAttribution, true));
mapboxMapOptions.attributionGravity(typedArray.getInt(
@@ -251,10 +247,9 @@ public class MapboxMapOptions implements Parcelable {
mapboxMapOptions.locationEnabled(typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_myLocation, false));
mapboxMapOptions.myLocationForegroundTintColor(
- typedArray.getColor(R.styleable.mapbox_MapView_mapbox_myLocationTintColor,
- ColorUtils.getPrimaryColor(context)));
+ typedArray.getColor(R.styleable.mapbox_MapView_mapbox_myLocationTintColor, UNDEFINED_COLOR));
mapboxMapOptions.myLocationBackgroundTintColor(
- typedArray.getColor(R.styleable.mapbox_MapView_mapbox_myLocationBackgroundTintColor, Color.WHITE));
+ typedArray.getColor(R.styleable.mapbox_MapView_mapbox_myLocationBackgroundTintColor, UNDEFINED_COLOR));
Drawable foregroundDrawable = typedArray.getDrawable(R.styleable.mapbox_MapView_mapbox_myLocationDrawable);
if (foregroundDrawable == null) {
@@ -290,8 +285,16 @@ public class MapboxMapOptions implements Parcelable {
mapboxMapOptions.myLocationAccuracyTint(
typedArray.getColor(R.styleable.mapbox_MapView_mapbox_myLocationAccuracyTintColor,
ColorUtils.getPrimaryColor(context)));
+ mapboxMapOptions.myLocationAccuracyThreshold(
+ typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_myLocationAccuracyThreshold, 0));
mapboxMapOptions.textureMode(
typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_renderTextureMode, false));
+ mapboxMapOptions.setPrefetchesTiles(
+ typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_enableTilePrefetch, true));
+ mapboxMapOptions.renderSurfaceOnTop(
+ typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_enableZMediaOverlay, false));
+ mapboxMapOptions.localIdeographFontFamily(
+ typedArray.getString(R.styleable.mapbox_MapView_mapbox_localIdeographFontFamily));
} finally {
typedArray.recycle();
}
@@ -378,7 +381,7 @@ public class MapboxMapOptions implements Parcelable {
/**
* Specifies the gravity state of mapbox_compass_icon for a map view.
*
- * @param gravity see {@link android.view.Gravity}
+ * @param gravity Android SDK Gravity.
* @return This
*/
public MapboxMapOptions compassGravity(int gravity) {
@@ -439,7 +442,7 @@ public class MapboxMapOptions implements Parcelable {
/**
* Specifies the gravity state of logo for a map view.
*
- * @param gravity see {@link android.view.Gravity}
+ * @param gravity Android SDK Gravity.
* @return This
*/
public MapboxMapOptions logoGravity(int gravity) {
@@ -472,7 +475,7 @@ public class MapboxMapOptions implements Parcelable {
/**
* Specifies the gravity state of attribution for a map view.
*
- * @param gravity see {@link android.view.Gravity}
+ * @param gravity Android SDK Gravity.
* @return This
*/
public MapboxMapOptions attributionGravity(int gravity) {
@@ -638,7 +641,7 @@ public class MapboxMapOptions implements Parcelable {
/**
* Set the background tint color of MyLocationView.
*
- * @param myLocationBackgroundTintColor the color to tint the background
+ * @param myLocationBackgroundTintColor the color to tint the background drawable
* @return This
*/
public MapboxMapOptions myLocationBackgroundTintColor(@ColorInt int myLocationBackgroundTintColor) {
@@ -680,15 +683,28 @@ public class MapboxMapOptions implements Parcelable {
}
/**
- * Enable TextureView as rendered surface.
+ * Set accuracy circle threshold. Circle won't be displayed if accuracy is below set value.
+ *
+ * @param myLocationAccuracyThreshold Value of accuracy (in meters), below which circle won't be displayed
+ * @return This
+ */
+ public MapboxMapOptions myLocationAccuracyThreshold(float myLocationAccuracyThreshold) {
+ this.myLocationAccuracyThreshold = myLocationAccuracyThreshold;
+ return this;
+ }
+
+ /**
+ * Enable {@link android.view.TextureView} as rendered surface.
* <p>
- * Since the 4.2.0 release we replaced our TextureView with an SurfaceView implemenation.
- * Enabling this option will use the deprecated TextureView instead.
+ * Since the 5.2.0 release we replaced our TextureView with an {@link android.opengl.GLSurfaceView}
+ * implementation. Enabling this option will use the {@link android.view.TextureView} instead.
+ * {@link android.view.TextureView} can be useful in situations where you need to animate, scale
+ * or transform the view. This comes at a siginficant performance penalty and should not be considered
+ * unless absolutely needed.
* </p>
*
* @param textureMode True to enable texture mode
* @return This
- * @deprecated As of the 4.2.0 release, using TextureView is deprecated.
*/
public MapboxMapOptions textureMode(boolean textureMode) {
this.textureMode = textureMode;
@@ -696,6 +712,59 @@ public class MapboxMapOptions implements Parcelable {
}
/**
+ * Enable tile pre-fetching. Loads tiles at a lower zoom-level to pre-render
+ * a low resolution preview while more detailed tiles are loaded.
+ * Enabled by default
+ *
+ * @param enable true to enable
+ * @return This
+ */
+ public MapboxMapOptions setPrefetchesTiles(boolean enable) {
+ this.prefetchesTiles = enable;
+ return this;
+ }
+
+ /**
+ * Set the font-family for generating glyphs locally for ideographs in the ‘CJK Unified Ideographs’
+ * and ‘Hangul Syllables’ ranges.
+ *
+ * @param fontFamily font family for local ideograph generation.
+ * @return This
+ */
+ public MapboxMapOptions localIdeographFontFamily(String fontFamily) {
+ this.localIdeographFontFamily = fontFamily;
+ return this;
+ }
+
+ /**
+ * Check whether tile pre-fetching is enabled.
+ *
+ * @return true if enabled
+ */
+ public boolean getPrefetchesTiles() {
+ return prefetchesTiles;
+ }
+
+
+ /**
+ * Set the flag to render the map surface on top of another surface.
+ *
+ * @param renderOnTop true if this map is shown on top of another one, false if bottom.
+ */
+ public void renderSurfaceOnTop(boolean renderOnTop) {
+ this.zMediaOverlay = renderOnTop;
+ }
+
+ /**
+ * Get the flag to render the map surface on top of another surface.
+ *
+ * @return true if this map is
+ */
+ public boolean getRenderSurfaceOnTop() {
+ return zMediaOverlay;
+ }
+
+ /**
* Get the current configured API endpoint base URL.
*
* @return Base URL to be used API endpoint.
@@ -944,6 +1013,7 @@ public class MapboxMapOptions implements Parcelable {
*
* @return the tint color
*/
+ @ColorInt
public int getMyLocationForegroundTintColor() {
return myLocationForegroundTintColor;
}
@@ -953,6 +1023,7 @@ public class MapboxMapOptions implements Parcelable {
*
* @return the tint color
*/
+ @ColorInt
public int getMyLocationBackgroundTintColor() {
return myLocationBackgroundTintColor;
}
@@ -985,6 +1056,15 @@ public class MapboxMapOptions implements Parcelable {
}
/**
+ * Returns current accuracy threshold value (in meters).
+ *
+ * @return Value of accuracy threshold (in meters), below which circle won't be displayed
+ */
+ public float getMyLocationAccuracyThreshold() {
+ return myLocationAccuracyThreshold;
+ }
+
+ /**
* Get the current configured debug state for a map view.
*
* @return True indicates debug is enabled.
@@ -994,15 +1074,24 @@ public class MapboxMapOptions implements Parcelable {
}
/**
- * Returns true if TextureView is being used a render view.
+ * Returns true if TextureView is being used the render view.
*
* @return True if TextureView is used.
- * @deprecated As of the 4.2.0 release, using TextureView is deprecated.
*/
public boolean getTextureMode() {
return textureMode;
}
+ /**
+ * Returns the font-family for locally overriding generation of glyphs in the
+ * ‘CJK Unified Ideographs’ and ‘Hangul Syllables’ ranges.
+ *
+ * @return Local ideograph font family name.
+ */
+ public String getLocalIdeographFontFamily() {
+ return localIdeographFontFamily;
+ }
+
public static final Parcelable.Creator<MapboxMapOptions> CREATOR = new Parcelable.Creator<MapboxMapOptions>() {
public MapboxMapOptions createFromParcel(Parcel in) {
return new MapboxMapOptions(in);
@@ -1028,7 +1117,7 @@ public class MapboxMapOptions implements Parcelable {
dest.writeIntArray(compassMargins);
dest.writeByte((byte) (fadeCompassFacingNorth ? 1 : 0));
dest.writeParcelable(compassImage != null
- ? getBitmapFromDrawable(compassImage) : null, flags);
+ ? BitmapUtils.getBitmapFromDrawable(compassImage) : null, flags);
dest.writeByte((byte) (logoEnabled ? 1 : 0));
dest.writeInt(logoGravity);
@@ -1052,20 +1141,24 @@ public class MapboxMapOptions implements Parcelable {
dest.writeByte((byte) (myLocationEnabled ? 1 : 0));
dest.writeParcelable(myLocationForegroundDrawable != null
- ? getBitmapFromDrawable(myLocationForegroundDrawable) : null, flags);
+ ? BitmapUtils.getBitmapFromDrawable(myLocationForegroundDrawable) : null, flags);
dest.writeParcelable(myLocationForegroundBearingDrawable != null
- ? getBitmapFromDrawable(myLocationForegroundBearingDrawable) : null, flags);
+ ? BitmapUtils.getBitmapFromDrawable(myLocationForegroundBearingDrawable) : null, flags);
dest.writeParcelable(myLocationBackgroundDrawable != null
- ? getBitmapFromDrawable(myLocationBackgroundDrawable) : null, flags);
+ ? BitmapUtils.getBitmapFromDrawable(myLocationBackgroundDrawable) : null, flags);
dest.writeInt(myLocationForegroundTintColor);
dest.writeInt(myLocationBackgroundTintColor);
dest.writeIntArray(myLocationBackgroundPadding);
dest.writeInt(myLocationAccuracyAlpha);
dest.writeInt(myLocationAccuracyTintColor);
+ dest.writeFloat(myLocationAccuracyThreshold);
dest.writeString(style);
dest.writeString(apiBaseUrl);
dest.writeByte((byte) (textureMode ? 1 : 0));
+ dest.writeByte((byte) (prefetchesTiles ? 1 : 0));
+ dest.writeByte((byte) (zMediaOverlay ? 1 : 0));
+ dest.writeString(localIdeographFontFamily);
}
@Override
@@ -1150,6 +1243,9 @@ public class MapboxMapOptions implements Parcelable {
if (myLocationAccuracyAlpha != options.myLocationAccuracyAlpha) {
return false;
}
+ if (myLocationAccuracyThreshold != options.myLocationAccuracyThreshold) {
+ return false;
+ }
if (cameraPosition != null ? !cameraPosition.equals(options.cameraPosition) : options.cameraPosition != null) {
return false;
}
@@ -1186,6 +1282,16 @@ public class MapboxMapOptions implements Parcelable {
if (apiBaseUrl != null ? !apiBaseUrl.equals(options.apiBaseUrl) : options.apiBaseUrl != null) {
return false;
}
+ if (prefetchesTiles != options.prefetchesTiles) {
+ return false;
+ }
+ if (zMediaOverlay != options.zMediaOverlay) {
+ return false;
+ }
+ if (localIdeographFontFamily != options.localIdeographFontFamily) {
+ return false;
+ }
+
return false;
}
@@ -1227,9 +1333,14 @@ public class MapboxMapOptions implements Parcelable {
result = 31 * result + Arrays.hashCode(myLocationBackgroundPadding);
result = 31 * result + myLocationAccuracyTintColor;
result = 31 * result + myLocationAccuracyAlpha;
+ result = 31 * result + (myLocationAccuracyThreshold != +0.0f
+ ? Float.floatToIntBits(myLocationAccuracyThreshold) : 0);
result = 31 * result + (apiBaseUrl != null ? apiBaseUrl.hashCode() : 0);
result = 31 * result + (textureMode ? 1 : 0);
result = 31 * result + (style != null ? style.hashCode() : 0);
+ result = 31 * result + (prefetchesTiles ? 1 : 0);
+ result = 31 * result + (zMediaOverlay ? 1 : 0);
+ result = 31 * result + (localIdeographFontFamily != null ? localIdeographFontFamily.hashCode() : 0);
return result;
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MarkerContainer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MarkerContainer.java
index 306ad59b8d..2c2f07a112 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MarkerContainer.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MarkerContainer.java
@@ -18,8 +18,6 @@ import com.mapbox.mapboxsdk.annotations.MarkerViewManager;
import java.util.ArrayList;
import java.util.List;
-import timber.log.Timber;
-
/**
* Encapsulates {@link Marker}'s functionality.
*/
@@ -55,7 +53,7 @@ class MarkerContainer implements Markers {
mapboxMap) {
int count = markerOptionsList.size();
List<Marker> markers = new ArrayList<>(count);
- if (count > 0) {
+ if (nativeMapView != null && count > 0) {
BaseMarkerOptions markerOptions;
Marker marker;
for (int i = 0; i < count; i++) {
@@ -65,26 +63,13 @@ class MarkerContainer implements Markers {
}
if (markers.size() > 0) {
- long[] ids = null;
- if (nativeMapView != null) {
- ids = nativeMapView.addMarkers(markers);
- }
-
- long id = 0;
- Marker m;
- for (int i = 0; i < markers.size(); i++) {
- m = markers.get(i);
- m.setMapboxMap(mapboxMap);
- if (ids != null) {
- id = ids[i];
- } else {
- // unit test
- id++;
- }
- m.setId(id);
- annotations.put(id, m);
+ long[] ids = nativeMapView.addMarkers(markers);
+ for (int i = 0; i < ids.length; i++) {
+ Marker createdMarker = markers.get(i);
+ createdMarker.setMapboxMap(mapboxMap);
+ createdMarker.setId(ids[i]);
+ annotations.put(ids[i], createdMarker);
}
-
}
}
return markers;
@@ -92,11 +77,6 @@ class MarkerContainer implements Markers {
@Override
public void update(@NonNull Marker updatedMarker, @NonNull MapboxMap mapboxMap) {
- if (!isAddedToMap(updatedMarker)) {
- Timber.w("Attempting to update non-added Marker with value %s", updatedMarker);
- return;
- }
-
ensureIconLoaded(updatedMarker, mapboxMap);
nativeMapView.updateMarker(updatedMarker);
annotations.setValueAt(annotations.indexOfKey(updatedMarker.getId()), updatedMarker);
@@ -118,15 +98,8 @@ class MarkerContainer implements Markers {
@NonNull
@Override
public List<Marker> obtainAllIn(@NonNull RectF rectangle) {
- // convert Rectangle to be density depedent
- float pixelRatio = nativeMapView.getPixelRatio();
- RectF rect = new RectF(rectangle.left / pixelRatio,
- rectangle.top / pixelRatio,
- rectangle.right / pixelRatio,
- rectangle.bottom / pixelRatio);
-
+ RectF rect = nativeMapView.getDensityDependantRectangle(rectangle);
long[] ids = nativeMapView.queryPointAnnotations(rect);
-
List<Long> idsList = new ArrayList<>(ids.length);
for (long id : ids) {
idsList.add(id);
@@ -237,10 +210,6 @@ class MarkerContainer implements Markers {
return marker;
}
- private boolean isAddedToMap(Annotation annotation) {
- return annotation != null && annotation.getId() != -1 && annotations.indexOfKey(annotation.getId()) != -1;
- }
-
private void ensureIconLoaded(Marker marker, MapboxMap mapboxMap) {
if (!(marker instanceof MarkerView)) {
iconManager.ensureIconLoaded(marker, mapboxMap);
@@ -261,6 +230,7 @@ class MarkerContainer implements Markers {
if (icon == null) {
icon = IconFactory.getInstance(mapView.getContext()).defaultMarkerView();
}
+ iconManager.loadIconForMarkerView(marker);
marker.setIcon(icon);
return marker;
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java
index c0586a6449..f1635c898f 100755
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java
@@ -1,17 +1,15 @@
package com.mapbox.mapboxsdk.maps;
-import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.PointF;
import android.graphics.RectF;
-import android.os.Build;
+import android.os.AsyncTask;
import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.DisplayMetrics;
-import android.view.Surface;
import com.mapbox.mapboxsdk.LibraryLoader;
import com.mapbox.mapboxsdk.annotations.Icon;
@@ -19,10 +17,10 @@ import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.Polygon;
import com.mapbox.mapboxsdk.annotations.Polyline;
import com.mapbox.mapboxsdk.camera.CameraPosition;
-import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.geometry.ProjectedMeters;
+import com.mapbox.mapboxsdk.maps.renderer.MapRenderer;
import com.mapbox.mapboxsdk.storage.FileSource;
import com.mapbox.mapboxsdk.style.layers.CannotAddLayerException;
import com.mapbox.mapboxsdk.style.layers.Filter;
@@ -32,12 +30,14 @@ import com.mapbox.mapboxsdk.style.sources.CannotAddSourceException;
import com.mapbox.mapboxsdk.style.sources.Source;
import com.mapbox.mapboxsdk.utils.BitmapUtils;
import com.mapbox.services.commons.geojson.Feature;
+import com.mapbox.services.commons.geojson.Geometry;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.Map;
import timber.log.Timber;
@@ -56,12 +56,12 @@ final class NativeMapView {
//Hold a reference to prevent it from being GC'd as long as it's used on the native side
private final FileSource fileSource;
+ // Used to schedule work on the MapRenderer Thread
+ private MapRenderer mapRenderer;
+
// Device density
private final float pixelRatio;
- // Listeners for Map change events
- private CopyOnWriteArrayList<MapView.OnMapChangedListener> onMapChangedListeners;
-
// Listener invoked to return a bitmap of the map
private MapboxMap.SnapshotReadyCallback snapshotReadyCallback;
@@ -73,32 +73,15 @@ final class NativeMapView {
// Constructors
//
- public NativeMapView(MapView mapView) {
+ public NativeMapView(final MapView mapView, MapRenderer mapRenderer) {
+ this.mapRenderer = mapRenderer;
+ this.mapView = mapView;
+
Context context = mapView.getContext();
fileSource = FileSource.getInstance(context);
-
pixelRatio = context.getResources().getDisplayMetrics().density;
- int availableProcessors = Runtime.getRuntime().availableProcessors();
- ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
- ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
- activityManager.getMemoryInfo(memoryInfo);
- long totalMemory = memoryInfo.availMem;
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
- totalMemory = memoryInfo.totalMem;
- }
-
- if (availableProcessors < 0) {
- throw new IllegalArgumentException("availableProcessors cannot be negative.");
- }
-
- if (totalMemory < 0) {
- throw new IllegalArgumentException("totalMemory cannot be negative.");
- }
- onMapChangedListeners = new CopyOnWriteArrayList<>();
- this.mapView = mapView;
- String programCacheDir = context.getCacheDir().getAbsolutePath();
- nativeInitialize(this, fileSource, pixelRatio, programCacheDir, availableProcessors, totalMemory);
+ nativeInitialize(this, fileSource, mapRenderer, pixelRatio);
}
//
@@ -107,9 +90,10 @@ final class NativeMapView {
private boolean isDestroyedOn(String callingMethod) {
if (destroyed && !TextUtils.isEmpty(callingMethod)) {
- Timber.e(String.format(MapboxConstants.MAPBOX_LOCALE,
+ Timber.e(
"You're calling `%s` after the `MapView` was destroyed, were you invoking it after `onDestroy()`?",
- callingMethod));
+ callingMethod
+ );
}
return destroyed;
}
@@ -120,60 +104,12 @@ final class NativeMapView {
destroyed = true;
}
- public void initializeDisplay() {
- if (isDestroyedOn("initializeDisplay")) {
- return;
- }
- nativeInitializeDisplay();
- }
-
- public void terminateDisplay() {
- if (isDestroyedOn("terminateDisplay")) {
- return;
- }
- nativeTerminateDisplay();
- }
-
- public void initializeContext() {
- if (isDestroyedOn("initializeContext")) {
- return;
- }
- nativeInitializeContext();
- }
-
- public void terminateContext() {
- if (isDestroyedOn("terminateContext")) {
- return;
- }
- nativeTerminateContext();
- }
-
- public void createSurface(Surface surface) {
- if (isDestroyedOn("createSurface")) {
- return;
- }
- nativeCreateSurface(surface);
- }
-
- public void destroySurface() {
- if (isDestroyedOn("destroySurface")) {
- return;
- }
- nativeDestroySurface();
- }
-
public void update() {
if (isDestroyedOn("update")) {
return;
}
- nativeUpdate();
- }
- public void render() {
- if (isDestroyedOn("render")) {
- return;
- }
- nativeRender();
+ mapRenderer.requestRender();
}
public void resizeView(int width, int height) {
@@ -194,41 +130,18 @@ final class NativeMapView {
if (width > 65535) {
// we have seen edge cases where devices return incorrect values #6111
Timber.e("Device returned an out of range width size, "
- + "capping value at 65535 instead of " + width);
+ + "capping value at 65535 instead of %s", width);
width = 65535;
}
if (height > 65535) {
// we have seen edge cases where devices return incorrect values #6111
Timber.e("Device returned an out of range height size, "
- + "capping value at 65535 instead of " + height);
+ + "capping value at 65535 instead of %s", height);
height = 65535;
}
- nativeResizeView(width, height);
- }
-
- public void resizeFramebuffer(int fbWidth, int fbHeight) {
- if (isDestroyedOn("resizeFramebuffer")) {
- return;
- }
- if (fbWidth < 0) {
- throw new IllegalArgumentException("fbWidth cannot be negative.");
- }
- if (fbHeight < 0) {
- throw new IllegalArgumentException("fbHeight cannot be negative.");
- }
-
- if (fbWidth > 65535) {
- throw new IllegalArgumentException(
- "fbWidth cannot be greater than 65535.");
- }
-
- if (fbHeight > 65535) {
- throw new IllegalArgumentException(
- "fbHeight cannot be greater than 65535.");
- }
- nativeResizeFramebuffer(fbWidth, fbHeight);
+ nativeResizeView(width, height);
}
public void setStyleUrl(String url) {
@@ -323,6 +236,13 @@ final class NativeMapView {
return nativeGetCameraForLatLngBounds(latLngBounds);
}
+ public CameraPosition getCameraForGeometry(Geometry geometry, double bearing) {
+ if (isDestroyedOn("getCameraForGeometry")) {
+ return null;
+ }
+ return nativeGetCameraForGeometry(geometry, bearing);
+ }
+
public void resetPosition() {
if (isDestroyedOn("resetPosition")) {
return;
@@ -551,6 +471,13 @@ final class NativeMapView {
return nativeQueryPointAnnotations(rect);
}
+ public long[] queryShapeAnnotations(RectF rectF) {
+ if (isDestroyedOn("queryShapeAnnotations")) {
+ return new long[] {};
+ }
+ return nativeQueryShapeAnnotations(rectF);
+ }
+
public void addAnnotationIcon(String symbol, int width, int height, float scale, byte[] pixels) {
if (isDestroyedOn("addAnnotationIcon")) {
return;
@@ -558,6 +485,13 @@ final class NativeMapView {
nativeAddAnnotationIcon(symbol, width, height, scale, pixels);
}
+ public void removeAnnotationIcon(String symbol) {
+ if (isDestroyedOn("removeAnnotationIcon")) {
+ return;
+ }
+ nativeRemoveAnnotationIcon(symbol);
+ }
+
public void setVisibleCoordinateBounds(LatLng[] coordinates, RectF padding, double direction, long duration) {
if (isDestroyedOn("setVisibleCoordinateBounds")) {
return;
@@ -593,13 +527,6 @@ final class NativeMapView {
return nativeGetDebug();
}
- public void setEnableFps(boolean enable) {
- if (isDestroyedOn("setEnableFps")) {
- return;
- }
- nativeSetEnableFps(enable);
- }
-
public boolean isFullyLoaded() {
if (isDestroyedOn("isFullyLoaded")) {
return false;
@@ -689,6 +616,20 @@ final class NativeMapView {
return nativeGetCameraPosition();
}
+ public void setPrefetchesTiles(boolean enable) {
+ if (isDestroyedOn("setPrefetchesTiles")) {
+ return;
+ }
+ nativeSetPrefetchesTiles(enable);
+ }
+
+ public boolean getPrefetchesTiles() {
+ if (isDestroyedOn("getPrefetchesTiles")) {
+ return false;
+ }
+ return nativeGetPrefetchesTiles();
+ }
+
// Runtime style Api
public long getTransitionDuration() {
@@ -792,7 +733,7 @@ final class NativeMapView {
if (isDestroyedOn("addSource")) {
return;
}
- nativeAddSource(source.getNativePtr());
+ nativeAddSource(source, source.getNativePtr());
}
@Nullable
@@ -800,14 +741,15 @@ final class NativeMapView {
if (isDestroyedOn("removeSource")) {
return null;
}
- return nativeRemoveSourceById(sourceId);
+ Source source = getSource(sourceId);
+ return removeSource(source);
}
public Source removeSource(@NonNull Source source) {
if (isDestroyedOn("removeSource")) {
return null;
}
- nativeRemoveSource(source.getNativePtr());
+ nativeRemoveSource(source, source.getNativePtr());
return source;
}
@@ -815,6 +757,7 @@ final class NativeMapView {
if (isDestroyedOn("addImage")) {
return;
}
+
// Check/correct config
if (image.getConfig() != Bitmap.Config.ARGB_8888) {
image = image.copy(Bitmap.Config.ARGB_8888, false);
@@ -831,6 +774,14 @@ final class NativeMapView {
nativeAddImage(name, image.getWidth(), image.getHeight(), pixelRatio, buffer.array());
}
+ public void addImages(@NonNull HashMap<String, Bitmap> bitmapHashMap) {
+ if (isDestroyedOn("addImages")) {
+ return;
+ }
+ //noinspection unchecked
+ new BitmapImageConversionTask(this).execute(bitmapHashMap);
+ }
+
public void removeImage(String name) {
if (isDestroyedOn("removeImage")) {
return;
@@ -838,6 +789,13 @@ final class NativeMapView {
nativeRemoveImage(name);
}
+ public Bitmap getImage(String name) {
+ if (isDestroyedOn("getImage")) {
+ return null;
+ }
+ return nativeGetImage(name);
+ }
+
// Feature querying
@NonNull
@@ -869,13 +827,6 @@ final class NativeMapView {
return features != null ? Arrays.asList(features) : new ArrayList<Feature>();
}
- public void scheduleTakeSnapshot() {
- if (isDestroyedOn("scheduleTakeSnapshot")) {
- return;
- }
- nativeTakeSnapshot();
- }
-
public void setApiBaseUrl(String baseUrl) {
if (isDestroyedOn("setApiBaseUrl")) {
return;
@@ -894,33 +845,23 @@ final class NativeMapView {
return pixelRatio;
}
+ RectF getDensityDependantRectangle(final RectF rectangle) {
+ return new RectF(
+ rectangle.left / pixelRatio,
+ rectangle.top / pixelRatio,
+ rectangle.right / pixelRatio,
+ rectangle.bottom / pixelRatio
+ );
+ }
+
//
// Callbacks
//
- protected void onInvalidate() {
- if (mapView != null) {
- mapView.onInvalidate();
- }
- }
-
protected void onMapChanged(int rawChange) {
- if (onMapChangedListeners != null) {
- for (MapView.OnMapChangedListener onMapChangedListener : onMapChangedListeners) {
- try {
- onMapChangedListener.onMapChanged(rawChange);
- } catch (RuntimeException err) {
- Timber.e("Exception (%s) in MapView.OnMapChangedListener: %s", err.getClass(), err.getMessage());
- }
- }
- }
- }
-
- protected void onFpsChanged(double fps) {
- if (isDestroyedOn("OnFpsChanged")) {
- return;
+ if (mapView != null) {
+ mapView.onMapChange(rawChange);
}
- mapView.onFpsChanged(fps);
}
protected void onSnapshotReady(Bitmap mapContent) {
@@ -940,33 +881,13 @@ final class NativeMapView {
private native void nativeInitialize(NativeMapView nativeMapView,
FileSource fileSource,
- float pixelRatio,
- String programCacheDir,
- int availableProcessors,
- long totalMemory);
+ MapRenderer mapRenderer,
+ float pixelRatio);
private native void nativeDestroy();
- private native void nativeInitializeDisplay();
-
- private native void nativeTerminateDisplay();
-
- private native void nativeInitializeContext();
-
- private native void nativeTerminateContext();
-
- private native void nativeCreateSurface(Object surface);
-
- private native void nativeDestroySurface();
-
- private native void nativeUpdate();
-
- private native void nativeRender();
-
private native void nativeResizeView(int width, int height);
- private native void nativeResizeFramebuffer(int fbWidth, int fbHeight);
-
private native void nativeSetStyleUrl(String url);
private native String nativeGetStyleUrl();
@@ -989,6 +910,8 @@ final class NativeMapView {
private native CameraPosition nativeGetCameraForLatLngBounds(LatLngBounds latLngBounds);
+ private native CameraPosition nativeGetCameraForGeometry(Geometry geometry, double bearing);
+
private native void nativeResetPosition();
private native double nativeGetPitch();
@@ -1033,8 +956,12 @@ final class NativeMapView {
private native long[] nativeQueryPointAnnotations(RectF rect);
+ private native long[] nativeQueryShapeAnnotations(RectF rect);
+
private native void nativeAddAnnotationIcon(String symbol, int width, int height, float scale, byte[] pixels);
+ private native void nativeRemoveAnnotationIcon(String symbol);
+
private native void nativeSetVisibleCoordinateBounds(LatLng[] coordinates, RectF padding,
double direction, long duration);
@@ -1046,8 +973,6 @@ final class NativeMapView {
private native boolean nativeGetDebug();
- private native void nativeSetEnableFps(boolean enable);
-
private native boolean nativeIsFullyLoaded();
private native void nativeSetReachability(boolean status);
@@ -1103,17 +1028,19 @@ final class NativeMapView {
private native Source nativeGetSource(String sourceId);
- private native void nativeAddSource(long nativeSourcePtr) throws CannotAddSourceException;
-
- private native Source nativeRemoveSourceById(String sourceId);
+ private native void nativeAddSource(Source source, long sourcePtr) throws CannotAddSourceException;
- private native void nativeRemoveSource(long sourcePtr);
+ private native void nativeRemoveSource(Source source, long sourcePtr);
private native void nativeAddImage(String name, int width, int height, float pixelRatio,
byte[] array);
+ private native void nativeAddImages(Image[] images);
+
private native void nativeRemoveImage(String name);
+ private native Bitmap nativeGetImage(String name);
+
private native void nativeUpdatePolygon(long polygonId, Polygon polygon);
private native void nativeUpdatePolyline(long polylineId, Polyline polyline);
@@ -1131,6 +1058,10 @@ final class NativeMapView {
private native Light nativeGetLight();
+ private native void nativeSetPrefetchesTiles(boolean enable);
+
+ private native boolean nativeGetPrefetchesTiles();
+
int getWidth() {
if (isDestroyedOn("")) {
return 0;
@@ -1150,11 +1081,13 @@ final class NativeMapView {
//
void addOnMapChangedListener(@NonNull MapView.OnMapChangedListener listener) {
- onMapChangedListeners.add(listener);
+ if (mapView != null) {
+ mapView.addOnMapChangedListener(listener);
+ }
}
void removeOnMapChangedListener(@NonNull MapView.OnMapChangedListener listener) {
- onMapChangedListeners.remove(listener);
+ mapView.removeOnMapChangedListener(listener);
}
//
@@ -1162,8 +1095,86 @@ final class NativeMapView {
//
void addSnapshotCallback(@NonNull MapboxMap.SnapshotReadyCallback callback) {
+ if (isDestroyedOn("addSnapshotCallback")) {
+ return;
+ }
snapshotReadyCallback = callback;
- scheduleTakeSnapshot();
- render();
+ nativeTakeSnapshot();
+ }
+
+ public void setOnFpsChangedListener(final MapboxMap.OnFpsChangedListener listener) {
+ mapRenderer.queueEvent(new Runnable() {
+
+ @Override
+ public void run() {
+ mapRenderer.setOnFpsChangedListener(new MapboxMap.OnFpsChangedListener() {
+
+ @Override
+ public void onFpsChanged(final double fps) {
+ mapView.post(new Runnable() {
+
+ @Override
+ public void run() {
+ listener.onFpsChanged(fps);
+ }
+
+ });
+ }
+
+ });
+ }
+
+ });
+ }
+
+
+ //
+ // Image conversion
+ //
+
+ private static class BitmapImageConversionTask extends AsyncTask<HashMap<String, Bitmap>, Void, List<Image>> {
+
+ private NativeMapView nativeMapView;
+
+ BitmapImageConversionTask(NativeMapView nativeMapView) {
+ this.nativeMapView = nativeMapView;
+ }
+
+ @Override
+ protected List<Image> doInBackground(HashMap<String, Bitmap>... params) {
+ HashMap<String, Bitmap> bitmapHashMap = params[0];
+
+ List<Image> images = new ArrayList<>();
+ ByteBuffer buffer;
+ String name;
+ Bitmap bitmap;
+
+ for (Map.Entry<String, Bitmap> stringBitmapEntry : bitmapHashMap.entrySet()) {
+ name = stringBitmapEntry.getKey();
+ bitmap = stringBitmapEntry.getValue();
+
+ if (bitmap.getConfig() != Bitmap.Config.ARGB_8888) {
+ bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, false);
+ }
+
+ buffer = ByteBuffer.allocate(bitmap.getByteCount());
+ bitmap.copyPixelsToBuffer(buffer);
+
+ float density = bitmap.getDensity() == Bitmap.DENSITY_NONE ? Bitmap.DENSITY_NONE : bitmap.getDensity();
+ float pixelRatio = density / DisplayMetrics.DENSITY_DEFAULT;
+
+ images.add(new Image(buffer.array(), pixelRatio, name, bitmap.getWidth(), bitmap.getHeight()));
+ }
+
+ return images;
+ }
+
+ @Override
+ protected void onPostExecute(List<Image> images) {
+ super.onPostExecute(images);
+ if (nativeMapView != null && !nativeMapView.isDestroyedOn("nativeAddImages")) {
+ nativeMapView.nativeAddImages(images.toArray(new Image[images.size()]));
+ }
+ }
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolygonContainer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolygonContainer.java
index bcb94a975c..016862bddc 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolygonContainer.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolygonContainer.java
@@ -11,8 +11,6 @@ import com.mapbox.mapboxsdk.annotations.PolygonOptions;
import java.util.ArrayList;
import java.util.List;
-import timber.log.Timber;
-
/**
* Encapsulates {@link Polygon}'s functionality.
*/
@@ -44,7 +42,7 @@ class PolygonContainer implements Polygons {
Polygon polygon;
List<Polygon> polygons = new ArrayList<>(count);
- if (count > 0) {
+ if (nativeMapView != null && count > 0) {
for (PolygonOptions polygonOptions : polygonOptionsList) {
polygon = polygonOptions.getPolygon();
if (!polygon.getPoints().isEmpty()) {
@@ -52,23 +50,12 @@ class PolygonContainer implements Polygons {
}
}
- long[] ids = null;
- if (nativeMapView != null) {
- ids = nativeMapView.addPolygons(polygons);
- }
-
- long id = 0;
- for (int i = 0; i < polygons.size(); i++) {
+ long[] ids = nativeMapView.addPolygons(polygons);
+ for (int i = 0; i < ids.length; i++) {
polygon = polygons.get(i);
polygon.setMapboxMap(mapboxMap);
- if (ids != null) {
- id = ids[i];
- } else {
- // unit test
- id++;
- }
- polygon.setId(id);
- annotations.put(id, polygon);
+ polygon.setId(ids[i]);
+ annotations.put(ids[i], polygon);
}
}
return polygons;
@@ -76,11 +63,6 @@ class PolygonContainer implements Polygons {
@Override
public void update(Polygon polygon) {
- if (!isAddedToMap(polygon)) {
- Timber.w("Attempting to update non-added Polygon with value %s", polygon);
- return;
- }
-
nativeMapView.updatePolygon(polygon);
annotations.setValueAt(annotations.indexOfKey(polygon.getId()), polygon);
}
@@ -97,8 +79,4 @@ class PolygonContainer implements Polygons {
}
return polygons;
}
-
- private boolean isAddedToMap(Annotation annotation) {
- return annotation != null && annotation.getId() != -1 && annotations.indexOfKey(annotation.getId()) != -1;
- }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolylineContainer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolylineContainer.java
index 7483f1082b..303b25fb55 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolylineContainer.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolylineContainer.java
@@ -11,8 +11,6 @@ import com.mapbox.mapboxsdk.annotations.PolylineOptions;
import java.util.ArrayList;
import java.util.List;
-import timber.log.Timber;
-
/**
* Encapsulates {@link Polyline}'s functionality.
*/
@@ -43,8 +41,7 @@ class PolylineContainer implements Polylines {
int count = polylineOptionsList.size();
Polyline polyline;
List<Polyline> polylines = new ArrayList<>(count);
-
- if (count > 0) {
+ if (nativeMapView != null && count > 0) {
for (PolylineOptions options : polylineOptionsList) {
polyline = options.getPolyline();
if (!polyline.getPoints().isEmpty()) {
@@ -52,25 +49,12 @@ class PolylineContainer implements Polylines {
}
}
- long[] ids = null;
- if (nativeMapView != null) {
- ids = nativeMapView.addPolylines(polylines);
- }
-
- long id = 0;
- Polyline p;
-
- for (int i = 0; i < polylines.size(); i++) {
- p = polylines.get(i);
- p.setMapboxMap(mapboxMap);
- if (ids != null) {
- id = ids[i];
- } else {
- // unit test
- id++;
- }
- p.setId(id);
- annotations.put(id, p);
+ long[] ids = nativeMapView.addPolylines(polylines);
+ for (int i = 0; i < ids.length; i++) {
+ Polyline polylineCreated = polylines.get(i);
+ polylineCreated.setMapboxMap(mapboxMap);
+ polylineCreated.setId(ids[i]);
+ annotations.put(ids[i], polylineCreated);
}
}
return polylines;
@@ -78,10 +62,6 @@ class PolylineContainer implements Polylines {
@Override
public void update(Polyline polyline) {
- if (!isAddedToMap(polyline)) {
- Timber.w("Attempting to update non-added Polyline with value %s", polyline);
- }
-
nativeMapView.updatePolyline(polyline);
annotations.setValueAt(annotations.indexOfKey(polyline.getId()), polyline);
}
@@ -98,8 +78,4 @@ class PolylineContainer implements Polylines {
}
return polylines;
}
-
- private boolean isAddedToMap(Annotation annotation) {
- return annotation != null && annotation.getId() != -1 && annotations.indexOfKey(annotation.getId()) != -1;
- }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java
index ff466c436c..16c73b1ca5 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java
@@ -6,6 +6,7 @@ import android.support.annotation.NonNull;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
+import com.mapbox.mapboxsdk.geometry.ProjectedMeters;
import com.mapbox.mapboxsdk.geometry.VisibleRegion;
/**
@@ -45,6 +46,20 @@ public class Projection {
}
/**
+ * Returns the spherical Mercator projected meters for a LatLng.
+ */
+ public ProjectedMeters getProjectedMetersForLatLng(LatLng latLng) {
+ return nativeMapView.projectedMetersForLatLng(latLng);
+ }
+
+ /**
+ * Returns the LatLng for a spherical Mercator projected meters.
+ */
+ public LatLng getLatLngForProjectedMeters(ProjectedMeters projectedMeters) {
+ return nativeMapView.latLngForProjectedMeters(projectedMeters);
+ }
+
+ /**
* <p>
* Returns the distance spanned by one pixel at the specified latitude and current zoom level.
* </p>
@@ -78,24 +93,23 @@ public class Projection {
* @return The projection of the viewing frustum in its current state.
*/
public VisibleRegion getVisibleRegion() {
- LatLngBounds.Builder builder = new LatLngBounds.Builder();
-
- float left = contentPadding[0];
- float right = nativeMapView.getWidth() - contentPadding[2];
- float top = contentPadding[1];
- float bottom = nativeMapView.getHeight() - contentPadding[3];
+ float left = 0;
+ float right = nativeMapView.getWidth();
+ float top = 0;
+ float bottom = nativeMapView.getHeight();
LatLng topLeft = fromScreenLocation(new PointF(left, top));
LatLng topRight = fromScreenLocation(new PointF(right, top));
LatLng bottomRight = fromScreenLocation(new PointF(right, bottom));
LatLng bottomLeft = fromScreenLocation(new PointF(left, bottom));
- builder.include(topLeft)
- .include(topRight)
- .include(bottomRight)
- .include(bottomLeft);
-
- return new VisibleRegion(topLeft, topRight, bottomLeft, bottomRight, builder.build());
+ return new VisibleRegion(topLeft, topRight, bottomLeft, bottomRight,
+ LatLngBounds.from(
+ topRight.getLatitude(),
+ topRight.getLongitude(),
+ bottomLeft.getLatitude(),
+ bottomLeft.getLongitude())
+ );
}
/**
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ShapeAnnotationContainer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ShapeAnnotationContainer.java
new file mode 100644
index 0000000000..6ded2f32fb
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ShapeAnnotationContainer.java
@@ -0,0 +1,38 @@
+package com.mapbox.mapboxsdk.maps;
+
+import android.graphics.RectF;
+import android.support.v4.util.LongSparseArray;
+
+import com.mapbox.mapboxsdk.annotations.Annotation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+class ShapeAnnotationContainer implements ShapeAnnotations {
+
+ private final NativeMapView nativeMapView;
+ private final LongSparseArray<Annotation> annotations;
+
+ ShapeAnnotationContainer(NativeMapView nativeMapView, LongSparseArray<Annotation> annotations) {
+ this.nativeMapView = nativeMapView;
+ this.annotations = annotations;
+ }
+
+ @Override
+ public List<Annotation> obtainAllIn(RectF rectangle) {
+ RectF rect = nativeMapView.getDensityDependantRectangle(rectangle);
+ long[] annotationIds = nativeMapView.queryShapeAnnotations(rect);
+ return getAnnotationsFromIds(annotationIds);
+ }
+
+ private List<Annotation> getAnnotationsFromIds(long[] annotationIds) {
+ List<Annotation> shapeAnnotations = new ArrayList<>();
+ for (long annotationId : annotationIds) {
+ Annotation annotation = annotations.get(annotationId);
+ if (annotation != null) {
+ shapeAnnotations.add(annotation);
+ }
+ }
+ return shapeAnnotations;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ShapeAnnotations.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ShapeAnnotations.java
new file mode 100644
index 0000000000..f9b2ca10db
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/ShapeAnnotations.java
@@ -0,0 +1,13 @@
+package com.mapbox.mapboxsdk.maps;
+
+import android.graphics.RectF;
+
+import com.mapbox.mapboxsdk.annotations.Annotation;
+
+import java.util.List;
+
+interface ShapeAnnotations {
+
+ List<Annotation> obtainAllIn(RectF rectF);
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java
index 77fea1a14a..6c90cd95ec 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/SupportMapFragment.java
@@ -76,6 +76,9 @@ public class SupportMapFragment extends Fragment {
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
map.onCreate(savedInstanceState);
+ if (onMapReadyCallback != null) {
+ map.getMapAsync(onMapReadyCallback);
+ }
}
/**
@@ -85,7 +88,6 @@ public class SupportMapFragment extends Fragment {
public void onStart() {
super.onStart();
map.onStart();
- map.getMapAsync(onMapReadyCallback);
}
/**
@@ -150,6 +152,10 @@ public class SupportMapFragment extends Fragment {
* @param onMapReadyCallback The callback to be invoked.
*/
public void getMapAsync(@NonNull final OnMapReadyCallback onMapReadyCallback) {
- this.onMapReadyCallback = onMapReadyCallback;
+ if (map == null) {
+ this.onMapReadyCallback = onMapReadyCallback;
+ } else {
+ map.getMapAsync(onMapReadyCallback);
+ }
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java
index 7dcd84de75..6eacbbaeaf 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/TrackingSettings.java
@@ -6,11 +6,11 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
+import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.constants.MyBearingTracking;
import com.mapbox.mapboxsdk.constants.MyLocationTracking;
-import com.mapbox.mapboxsdk.location.LocationSource;
import com.mapbox.mapboxsdk.maps.widgets.MyLocationView;
import com.mapbox.services.android.telemetry.location.LocationEngine;
import com.mapbox.services.android.telemetry.location.LocationEngineListener;
@@ -20,7 +20,11 @@ import timber.log.Timber;
/**
* Settings for the user location and bearing tracking of a MapboxMap.
+ *
+ * @deprecated use location layer plugin from
+ * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugins/locationlayer instead.
*/
+@Deprecated
public final class TrackingSettings {
private final MyLocationView myLocationView;
@@ -29,6 +33,8 @@ public final class TrackingSettings {
private final CameraZoomInvalidator zoomInvalidator;
private LocationEngine locationSource;
private LocationEngineListener myLocationListener;
+ private boolean locationChangeAnimationEnabled = true;
+ private boolean isCustomLocationSource;
private boolean myLocationEnabled;
private boolean dismissLocationTrackingOnGesture = true;
@@ -46,7 +52,7 @@ public final class TrackingSettings {
}
void initialise(MapboxMapOptions options) {
- locationSource = LocationSource.getLocationEngine(myLocationView.getContext());
+ locationSource = Mapbox.getLocationEngine();
setMyLocationEnabled(options.getLocationEnabled());
}
@@ -56,11 +62,16 @@ public final class TrackingSettings {
outState.putBoolean(MapboxConstants.STATE_MY_LOCATION_TRACKING_DISMISS, isDismissLocationTrackingOnGesture());
outState.putBoolean(MapboxConstants.STATE_MY_BEARING_TRACKING_DISMISS, isDismissBearingTrackingOnGesture());
outState.putBoolean(MapboxConstants.STATE_MY_LOCATION_ENABLED, isMyLocationEnabled());
+ outState.putBoolean(MapboxConstants.STATE_LOCATION_CHANGE_ANIMATION_ENABLED, isLocationChangeAnimationEnabled());
+ outState.putBoolean(MapboxConstants.STATE_USING_CUSTOM_LOCATION_SOURCE, isCustomLocationSource());
}
void onRestoreInstanceState(Bundle savedInstanceState) {
try {
- setMyLocationEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_MY_LOCATION_ENABLED));
+ setMyLocationEnabled(
+ savedInstanceState.getBoolean(MapboxConstants.STATE_MY_LOCATION_ENABLED),
+ savedInstanceState.getBoolean(MapboxConstants.STATE_USING_CUSTOM_LOCATION_SOURCE)
+ );
} catch (SecurityException ignore) {
// User did not accept location permissions
}
@@ -74,6 +85,8 @@ public final class TrackingSettings {
MapboxConstants.STATE_MY_LOCATION_TRACKING_DISMISS, true));
setDismissBearingTrackingOnGesture(savedInstanceState.getBoolean(
MapboxConstants.STATE_MY_BEARING_TRACKING_DISMISS, true));
+ setLocationChangeAnimationEnabled(savedInstanceState.getBoolean(
+ MapboxConstants.STATE_LOCATION_CHANGE_ANIMATION_ENABLED, true));
}
/**
@@ -91,6 +104,7 @@ public final class TrackingSettings {
*/
@UiThread
public void setMyLocationTrackingMode(@MyLocationTracking.Mode int myLocationTrackingMode) {
+ myLocationView.setLocationChangeAnimationEnabled(isLocationChangeAnimationEnabled());
myLocationView.setMyLocationTrackingMode(myLocationTrackingMode);
if (myLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) {
@@ -254,6 +268,26 @@ public final class TrackingSettings {
}
/**
+ * Returns whether location change animation is applied for {@link MyLocationTracking#TRACKING_FOLLOW}.
+ *
+ * @return True if animation is applied, false otherwise.
+ */
+ public boolean isLocationChangeAnimationEnabled() {
+ return locationChangeAnimationEnabled;
+ }
+
+ /**
+ * Set whether location change animation should be applied for {@link MyLocationTracking#TRACKING_FOLLOW}.
+ *
+ * @param locationChangeAnimationEnabled True if animation should be applied, false otherwise.
+ */
+ public void setLocationChangeAnimationEnabled(boolean locationChangeAnimationEnabled) {
+ this.locationChangeAnimationEnabled = locationChangeAnimationEnabled;
+
+ myLocationView.setLocationChangeAnimationEnabled(locationChangeAnimationEnabled);
+ }
+
+ /**
* Reset the tracking modes as necessary. Location tracking is reset if the map center is changed and not from
* location, bearing tracking if there is a rotation.
*
@@ -314,6 +348,10 @@ public final class TrackingSettings {
}
}
+ public boolean isCustomLocationSource() {
+ return isCustomLocationSource;
+ }
+
void setOnMyLocationTrackingModeChangeListener(MapboxMap.OnMyLocationTrackingModeChangeListener listener) {
this.onMyLocationTrackingModeChangeListener = listener;
}
@@ -332,16 +370,30 @@ public final class TrackingSettings {
}
void setMyLocationEnabled(boolean locationEnabled) {
+ setMyLocationEnabled(locationEnabled, isCustomLocationSource());
+ }
+
+ private void setMyLocationEnabled(boolean locationEnabled, boolean isCustomLocationSource) {
if (!PermissionsManager.areLocationPermissionsGranted(myLocationView.getContext())) {
Timber.e("Could not activate user location tracking: "
+ "user did not accept the permission or permissions were not requested.");
return;
}
myLocationEnabled = locationEnabled;
- myLocationView.setEnabled(locationEnabled);
+ this.isCustomLocationSource = isCustomLocationSource;
+ myLocationView.setEnabled(locationEnabled, isCustomLocationSource);
}
void setLocationSource(LocationEngine locationSource) {
+ if (this.locationSource != null && this.locationSource.equals(locationSource)) {
+ // this source is already active
+ return;
+ }
+
+ this.isCustomLocationSource = locationSource != null;
+ if (locationSource == null) {
+ locationSource = Mapbox.getLocationEngine();
+ }
this.locationSource = locationSource;
myLocationView.setLocationSource(locationSource);
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java
index 7f44e0de07..16c45ebea2 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java
@@ -79,7 +79,7 @@ final class Transform implements MapView.OnMapChangedListener {
@Override
public void onMapChanged(@MapView.MapChange int change) {
- if (change == REGION_DID_CHANGE_ANIMATED && cameraCancelableCallback != null) {
+ if (change == REGION_DID_CHANGE_ANIMATED) {
updateCameraPosition(invalidateCameraPosition());
if (cameraCancelableCallback != null) {
cameraCancelableCallback.onFinish();
@@ -93,14 +93,11 @@ final class Transform implements MapView.OnMapChangedListener {
@UiThread
final void moveCamera(MapboxMap mapboxMap, CameraUpdate update, MapboxMap.CancelableCallback callback) {
CameraPosition cameraPosition = update.getCameraPosition(mapboxMap);
- if (!cameraPosition.equals(this.cameraPosition)) {
+ if (isValidCameraPosition(cameraPosition)) {
trackingSettings.resetTrackingModesIfRequired(this.cameraPosition, cameraPosition, false);
cancelTransitions();
cameraChangeDispatcher.onCameraMoveStarted(OnCameraMoveStartedListener.REASON_API_ANIMATION);
mapView.jumpTo(cameraPosition.bearing, cameraPosition.target, cameraPosition.tilt, cameraPosition.zoom);
- if (callback != null) {
- callback.onFinish();
- }
cameraChangeDispatcher.onCameraIdle();
}
}
@@ -109,15 +106,15 @@ final class Transform implements MapView.OnMapChangedListener {
final void easeCamera(MapboxMap mapboxMap, CameraUpdate update, int durationMs, boolean easingInterpolator,
final MapboxMap.CancelableCallback callback, boolean isDismissable) {
CameraPosition cameraPosition = update.getCameraPosition(mapboxMap);
- if (!cameraPosition.equals(this.cameraPosition)) {
+ if (isValidCameraPosition(cameraPosition)) {
trackingSettings.resetTrackingModesIfRequired(this.cameraPosition, cameraPosition, isDismissable);
cancelTransitions();
cameraChangeDispatcher.onCameraMoveStarted(OnCameraMoveStartedListener.REASON_API_ANIMATION);
if (callback != null) {
cameraCancelableCallback = callback;
- mapView.addOnMapChangedListener(this);
}
+ mapView.addOnMapChangedListener(this);
mapView.easeTo(cameraPosition.bearing, cameraPosition.target, durationMs, cameraPosition.tilt,
cameraPosition.zoom, easingInterpolator);
}
@@ -127,21 +124,24 @@ final class Transform implements MapView.OnMapChangedListener {
final void animateCamera(MapboxMap mapboxMap, CameraUpdate update, int durationMs,
final MapboxMap.CancelableCallback callback) {
CameraPosition cameraPosition = update.getCameraPosition(mapboxMap);
- if (!cameraPosition.equals(this.cameraPosition)) {
+ if (isValidCameraPosition(cameraPosition)) {
trackingSettings.resetTrackingModesIfRequired(this.cameraPosition, cameraPosition, false);
cancelTransitions();
cameraChangeDispatcher.onCameraMoveStarted(OnCameraMoveStartedListener.REASON_API_ANIMATION);
if (callback != null) {
cameraCancelableCallback = callback;
- mapView.addOnMapChangedListener(this);
}
-
+ mapView.addOnMapChangedListener(this);
mapView.flyTo(cameraPosition.bearing, cameraPosition.target, durationMs, cameraPosition.tilt,
cameraPosition.zoom);
}
}
+ private boolean isValidCameraPosition(@Nullable CameraPosition cameraPosition) {
+ return cameraPosition != null && !cameraPosition.equals(this.cameraPosition);
+ }
+
@UiThread
@Nullable
CameraPosition invalidateCameraPosition() {
@@ -151,6 +151,10 @@ final class Transform implements MapView.OnMapChangedListener {
cameraChangeDispatcher.onCameraMove();
}
+ if (isComponentUpdateRequired(cameraPosition)) {
+ updateCameraPosition(cameraPosition);
+ }
+
this.cameraPosition = cameraPosition;
if (onCameraChangeListener != null) {
onCameraChangeListener.onCameraChange(this.cameraPosition);
@@ -159,6 +163,11 @@ final class Transform implements MapView.OnMapChangedListener {
return cameraPosition;
}
+ private boolean isComponentUpdateRequired(@NonNull CameraPosition cameraPosition) {
+ return this.cameraPosition != null && (this.cameraPosition.tilt != cameraPosition.tilt
+ || this.cameraPosition.bearing != cameraPosition.bearing);
+ }
+
void cancelTransitions() {
// notify user about cancel
cameraChangeDispatcher.onCameraMoveCanceled();
@@ -198,11 +207,29 @@ final class Transform implements MapView.OnMapChangedListener {
return cameraPosition.zoom;
}
+ double getRawZoom() {
+ return mapView.getZoom();
+ }
+
void zoom(boolean zoomIn, @NonNull PointF focalPoint) {
CameraPosition cameraPosition = invalidateCameraPosition();
if (cameraPosition != null) {
int newZoom = (int) Math.round(cameraPosition.zoom + (zoomIn ? 1 : -1));
setZoom(newZoom, focalPoint, MapboxConstants.ANIMATION_DURATION);
+ } else {
+ // we are not transforming, notify about being idle
+ cameraChangeDispatcher.onCameraIdle();
+ }
+ }
+
+ void zoom(double zoomAddition, @NonNull PointF focalPoint, long duration) {
+ CameraPosition cameraPosition = invalidateCameraPosition();
+ if (cameraPosition != null) {
+ int newZoom = (int) Math.round(cameraPosition.zoom + zoomAddition);
+ setZoom(newZoom, focalPoint, duration);
+ } else {
+ // we are not transforming, notify about being idle
+ cameraChangeDispatcher.onCameraIdle();
}
}
@@ -211,16 +238,18 @@ final class Transform implements MapView.OnMapChangedListener {
}
void setZoom(double zoom, @NonNull PointF focalPoint, long duration) {
- mapView.addOnMapChangedListener(new MapView.OnMapChangedListener() {
- @Override
- public void onMapChanged(int change) {
- if (change == MapView.REGION_DID_CHANGE_ANIMATED) {
- mapView.removeOnMapChangedListener(this);
- cameraChangeDispatcher.onCameraIdle();
+ if (mapView != null) {
+ mapView.addOnMapChangedListener(new MapView.OnMapChangedListener() {
+ @Override
+ public void onMapChanged(int change) {
+ if (change == MapView.REGION_DID_CHANGE_ANIMATED) {
+ cameraChangeDispatcher.onCameraIdle();
+ mapView.removeOnMapChangedListener(this);
+ }
}
- }
- });
- mapView.setZoom(zoom, focalPoint, duration);
+ });
+ mapView.setZoom(zoom, focalPoint, duration);
+ }
}
// Direction
@@ -315,7 +344,7 @@ final class Transform implements MapView.OnMapChangedListener {
mapView.addOnMapChangedListener(new MapView.OnMapChangedListener() {
@Override
public void onMapChanged(int change) {
- if (change == MapView.DID_FINISH_RENDERING_MAP_FULLY_RENDERED) {
+ if (change == MapView.REGION_DID_CHANGE_ANIMATED) {
mapView.removeOnMapChangedListener(this);
cameraChangeDispatcher.onCameraIdle();
}
@@ -331,7 +360,7 @@ final class Transform implements MapView.OnMapChangedListener {
void setMinZoom(double minZoom) {
if ((minZoom < MapboxConstants.MINIMUM_ZOOM) || (minZoom > MapboxConstants.MAXIMUM_ZOOM)) {
- Timber.e("Not setting minZoomPreference, value is in unsupported range: " + minZoom);
+ Timber.e("Not setting minZoomPreference, value is in unsupported range: %s", minZoom);
return;
}
mapView.setMinZoom(minZoom);
@@ -343,7 +372,7 @@ final class Transform implements MapView.OnMapChangedListener {
void setMaxZoom(double maxZoom) {
if ((maxZoom < MapboxConstants.MINIMUM_ZOOM) || (maxZoom > MapboxConstants.MAXIMUM_ZOOM)) {
- Timber.e("Not setting maxZoomPreference, value is in unsupported range: " + maxZoom);
+ Timber.e("Not setting maxZoomPreference, value is in unsupported range: %s", maxZoom);
return;
}
mapView.setMaxZoom(maxZoom);
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java
index 5f7b6c571b..0843828554 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java
@@ -3,11 +3,8 @@ package com.mapbox.mapboxsdk.maps;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.graphics.PointF;
-import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.annotation.ColorInt;
@@ -16,7 +13,6 @@ import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import android.support.v4.content.ContextCompat;
import android.support.v4.content.res.ResourcesCompat;
-import android.view.Gravity;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -25,10 +21,9 @@ import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.maps.widgets.CompassView;
+import com.mapbox.mapboxsdk.utils.BitmapUtils;
import com.mapbox.mapboxsdk.utils.ColorUtils;
-import java.io.ByteArrayOutputStream;
-
/**
* Settings for the user interface of a MapboxMap. To obtain this interface, call getUiSettings().
*/
@@ -37,8 +32,14 @@ public final class UiSettings {
private final FocalPointChangeListener focalPointChangeListener;
private final Projection projection;
private final CompassView compassView;
+ private final int[] compassMargins = new int[4];
+
private final ImageView attributionsView;
+ private final int[] attributionsMargins = new int[4];
+
private final View logoView;
+ private final int[] logoMargins = new int[4];
+
private float pixelRatio;
private boolean rotateGesturesEnabled = true;
@@ -165,13 +166,7 @@ public final class UiSettings {
outState.putInt(MapboxConstants.STATE_COMPASS_MARGIN_RIGHT, getCompassMarginRight());
outState.putBoolean(MapboxConstants.STATE_COMPASS_FADE_WHEN_FACING_NORTH, isCompassFadeWhenFacingNorth());
outState.putByteArray(MapboxConstants.STATE_COMPASS_IMAGE_BITMAP,
- convert(MapboxMapOptions.getBitmapFromDrawable(getCompassImage())));
- }
-
- private byte[] convert(Bitmap resource) {
- ByteArrayOutputStream stream = new ByteArrayOutputStream();
- resource.compress(Bitmap.CompressFormat.PNG, 100, stream);
- return stream.toByteArray();
+ BitmapUtils.getByteArrayFromDrawable(getCompassImage()));
}
private void restoreCompass(Bundle savedInstanceState) {
@@ -182,12 +177,8 @@ public final class UiSettings {
savedInstanceState.getInt(MapboxConstants.STATE_COMPASS_MARGIN_RIGHT),
savedInstanceState.getInt(MapboxConstants.STATE_COMPASS_MARGIN_BOTTOM));
setCompassFadeFacingNorth(savedInstanceState.getBoolean(MapboxConstants.STATE_COMPASS_FADE_WHEN_FACING_NORTH));
- setCompassImage(decode(savedInstanceState.getByteArray(MapboxConstants.STATE_COMPASS_IMAGE_BITMAP)));
- }
-
- private Drawable decode(byte[] bitmap) {
- Bitmap compass = BitmapFactory.decodeByteArray(bitmap, 0, bitmap.length);
- return new BitmapDrawable(compassView.getResources(), compass);
+ setCompassImage(BitmapUtils.getDrawableFromByteArray(
+ compassView.getContext(), savedInstanceState.getByteArray(MapboxConstants.STATE_COMPASS_IMAGE_BITMAP)));
}
private void initialiseLogo(MapboxMapOptions options, Resources resources) {
@@ -309,8 +300,7 @@ public final class UiSettings {
* </p>
* By default, the compass is in the top right corner.
*
- * @param gravity One of the values from {@link Gravity}.
- * @see Gravity
+ * @param gravity Android SDK Gravity.
*/
@UiThread
public void setCompassGravity(int gravity) {
@@ -370,7 +360,7 @@ public final class UiSettings {
*/
@UiThread
public void setCompassMargins(int left, int top, int right, int bottom) {
- setWidgetMargins(compassView, left, top, right, bottom);
+ setWidgetMargins(compassView, compassMargins, left, top, right, bottom);
}
/**
@@ -379,7 +369,7 @@ public final class UiSettings {
* @return The left margin in pixels
*/
public int getCompassMarginLeft() {
- return ((FrameLayout.LayoutParams) compassView.getLayoutParams()).leftMargin;
+ return compassMargins[0];
}
/**
@@ -388,7 +378,7 @@ public final class UiSettings {
* @return The top margin in pixels
*/
public int getCompassMarginTop() {
- return ((FrameLayout.LayoutParams) compassView.getLayoutParams()).topMargin;
+ return compassMargins[1];
}
/**
@@ -397,7 +387,7 @@ public final class UiSettings {
* @return The right margin in pixels
*/
public int getCompassMarginRight() {
- return ((FrameLayout.LayoutParams) compassView.getLayoutParams()).rightMargin;
+ return compassMargins[2];
}
/**
@@ -406,7 +396,7 @@ public final class UiSettings {
* @return The bottom margin in pixels
*/
public int getCompassMarginBottom() {
- return ((FrameLayout.LayoutParams) compassView.getLayoutParams()).bottomMargin;
+ return compassMargins[3];
}
/**
@@ -423,7 +413,8 @@ public final class UiSettings {
return;
}
- compassView.update(cameraPosition.bearing);
+ double clockwiseBearing = -cameraPosition.bearing;
+ compassView.update(clockwiseBearing);
}
/**
@@ -454,8 +445,7 @@ public final class UiSettings {
* </p>
* By default, the logo is in the bottom left corner.
*
- * @param gravity One of the values from {@link Gravity}.
- * @see Gravity
+ * @param gravity Android SDK Gravity.
*/
public void setLogoGravity(int gravity) {
setWidgetGravity(logoView, gravity);
@@ -480,7 +470,7 @@ public final class UiSettings {
* @param bottom The bottom margin in pixels.
*/
public void setLogoMargins(int left, int top, int right, int bottom) {
- setWidgetMargins(logoView, left, top, right, bottom);
+ setWidgetMargins(logoView, logoMargins, left, top, right, bottom);
}
/**
@@ -489,7 +479,7 @@ public final class UiSettings {
* @return The left margin in pixels
*/
public int getLogoMarginLeft() {
- return ((FrameLayout.LayoutParams) logoView.getLayoutParams()).leftMargin;
+ return logoMargins[0];
}
/**
@@ -498,7 +488,7 @@ public final class UiSettings {
* @return The top margin in pixels
*/
public int getLogoMarginTop() {
- return ((FrameLayout.LayoutParams) logoView.getLayoutParams()).topMargin;
+ return logoMargins[1];
}
/**
@@ -507,7 +497,7 @@ public final class UiSettings {
* @return The right margin in pixels
*/
public int getLogoMarginRight() {
- return ((FrameLayout.LayoutParams) logoView.getLayoutParams()).rightMargin;
+ return logoMargins[2];
}
/**
@@ -516,7 +506,7 @@ public final class UiSettings {
* @return The bottom margin in pixels
*/
public int getLogoMarginBottom() {
- return ((FrameLayout.LayoutParams) logoView.getLayoutParams()).bottomMargin;
+ return logoMargins[3];
}
/**
@@ -546,8 +536,7 @@ public final class UiSettings {
* </p>
* By default, the attribution is in the bottom left corner next to the Mapbox logo.
*
- * @param gravity One of the values from {@link Gravity}.
- * @see Gravity
+ * @param gravity Android SDK Gravity.
*/
public void setAttributionGravity(int gravity) {
setWidgetGravity(attributionsView, gravity);
@@ -571,7 +560,7 @@ public final class UiSettings {
* @param bottom The bottom margin in pixels.
*/
public void setAttributionMargins(int left, int top, int right, int bottom) {
- setWidgetMargins(attributionsView, left, top, right, bottom);
+ setWidgetMargins(attributionsView, attributionsMargins, left, top, right, bottom);
}
/**
@@ -598,7 +587,7 @@ public final class UiSettings {
* @return The left margin in pixels
*/
public int getAttributionMarginLeft() {
- return ((FrameLayout.LayoutParams) attributionsView.getLayoutParams()).leftMargin;
+ return attributionsMargins[0];
}
/**
@@ -607,7 +596,7 @@ public final class UiSettings {
* @return The top margin in pixels
*/
public int getAttributionMarginTop() {
- return ((FrameLayout.LayoutParams) attributionsView.getLayoutParams()).topMargin;
+ return attributionsMargins[1];
}
/**
@@ -616,7 +605,7 @@ public final class UiSettings {
* @return The right margin in pixels
*/
public int getAttributionMarginRight() {
- return ((FrameLayout.LayoutParams) attributionsView.getLayoutParams()).rightMargin;
+ return attributionsMargins[2];
}
/**
@@ -625,7 +614,7 @@ public final class UiSettings {
* @return The bottom margin in pixels
*/
public int getAttributionMarginBottom() {
- return ((FrameLayout.LayoutParams) attributionsView.getLayoutParams()).bottomMargin;
+ return attributionsMargins[3];
}
/**
@@ -929,7 +918,14 @@ public final class UiSettings {
view.setLayoutParams(layoutParams);
}
- private void setWidgetMargins(@NonNull final View view, int left, int top, int right, int bottom) {
+ private void setWidgetMargins(@NonNull final View view, int[] initMargins, int left, int top, int right, int bottom) {
+ // keep state of initially set margins
+ initMargins[0] = left;
+ initMargins[1] = top;
+ initMargins[2] = right;
+ initMargins[3] = bottom;
+
+ // convert inital margins with padding
int[] contentPadding = projection.getContentPadding();
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) view.getLayoutParams();
left += contentPadding[0];
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java
new file mode 100644
index 0000000000..fcee5bd179
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java
@@ -0,0 +1,142 @@
+package com.mapbox.mapboxsdk.maps.renderer;
+
+import android.content.Context;
+import android.support.annotation.CallSuper;
+
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.storage.FileSource;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+/**
+ * The {@link MapRenderer} encapsulates the GL thread.
+ * <p>
+ * Performs actions on the GL thread to manage the GL resources and
+ * render on the one end and acts as a scheduler to request work to
+ * be performed on the GL thread on the other.
+ */
+public abstract class MapRenderer implements MapRendererScheduler {
+
+ // Holds the pointer to the native peer after initialisation
+ private long nativePtr = 0;
+
+ private MapboxMap.OnFpsChangedListener onFpsChangedListener;
+
+ public MapRenderer(Context context, String localIdeographFontFamily) {
+
+ FileSource fileSource = FileSource.getInstance(context);
+ float pixelRatio = context.getResources().getDisplayMetrics().density;
+ String programCacheDir = context.getCacheDir().getAbsolutePath();
+ // Initialise native peer
+ nativeInitialize(this, fileSource, pixelRatio, programCacheDir, localIdeographFontFamily);
+ }
+
+ public void onStart() {
+ // Implement if needed
+ }
+
+ public void onPause() {
+ // Implement if needed
+ }
+
+ public void onResume() {
+ // Implement if needed
+ }
+
+ public void onStop() {
+ // Implement if needed
+ }
+
+ public void onDestroy() {
+ // Implement if needed
+ }
+
+ public void setOnFpsChangedListener(MapboxMap.OnFpsChangedListener listener) {
+ onFpsChangedListener = listener;
+ }
+
+ @CallSuper
+ protected void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ nativeOnSurfaceCreated();
+ }
+
+ @CallSuper
+ protected void onSurfaceChanged(GL10 gl, int width, int height) {
+ if (width < 0) {
+ throw new IllegalArgumentException("fbWidth cannot be negative.");
+ }
+
+ if (height < 0) {
+ throw new IllegalArgumentException("fbHeight cannot be negative.");
+ }
+
+ if (width > 65535) {
+ throw new IllegalArgumentException(
+ "fbWidth cannot be greater than 65535.");
+ }
+
+ if (height > 65535) {
+ throw new IllegalArgumentException(
+ "fbHeight cannot be greater than 65535.");
+ }
+
+ gl.glViewport(0, 0, width, height);
+ nativeOnSurfaceChanged(width, height);
+ }
+
+ @CallSuper
+ protected void onDrawFrame(GL10 gl) {
+ nativeRender();
+
+ if (onFpsChangedListener != null) {
+ updateFps();
+ }
+ }
+
+ /**
+ * May be called from any thread.
+ * <p>
+ * Called from the native peer to schedule work on the GL
+ * thread. Explicit override for easier to read jni code.
+ *
+ * @param runnable the runnable to execute
+ * @see MapRendererRunnable
+ */
+ @CallSuper
+ void queueEvent(MapRendererRunnable runnable) {
+ this.queueEvent((Runnable) runnable);
+ }
+
+ private native void nativeInitialize(MapRenderer self,
+ FileSource fileSource,
+ float pixelRatio,
+ String programCacheDir,
+ String localIdeographFontFamily);
+
+ @CallSuper
+ @Override
+ protected native void finalize() throws Throwable;
+
+ private native void nativeOnSurfaceCreated();
+
+ private native void nativeOnSurfaceChanged(int width, int height);
+
+ private native void nativeRender();
+
+ private long frames;
+ private long timeElapsed;
+
+ private void updateFps() {
+ frames++;
+ long currentTime = System.nanoTime();
+ double fps = 0;
+ if (currentTime - timeElapsed >= 1) {
+ fps = frames / ((currentTime - timeElapsed) / 1E9);
+ onFpsChangedListener.onFpsChanged(fps);
+ timeElapsed = currentTime;
+ frames = 0;
+ }
+ }
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererRunnable.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererRunnable.java
new file mode 100644
index 0000000000..28246fe578
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererRunnable.java
@@ -0,0 +1,29 @@
+package com.mapbox.mapboxsdk.maps.renderer;
+
+/**
+ * Peer class for {@link Runnable}s to be scheduled on the {@link MapRenderer} thread.
+ * The actual work is performed in the native peer.
+ */
+class MapRendererRunnable implements Runnable {
+
+ // Holds the pointer to the native peer after initialisation
+ private final long nativePtr;
+
+ /**
+ * Constructed from the native peer constructor
+ *
+ * @param nativePtr the native peer's memory address
+ */
+ MapRendererRunnable(long nativePtr) {
+ this.nativePtr = nativePtr;
+ }
+
+ @Override
+ public native void run();
+
+ @Override
+ protected native void finalize() throws Throwable;
+
+ private native void nativeInitialize();
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererScheduler.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererScheduler.java
new file mode 100644
index 0000000000..7ad4f124d8
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRendererScheduler.java
@@ -0,0 +1,13 @@
+package com.mapbox.mapboxsdk.maps.renderer;
+
+/**
+ * Can be used to schedule work on the map renderer
+ * thread or request a render.
+ */
+public interface MapRendererScheduler {
+
+ void requestRender();
+
+ void queueEvent(Runnable runnable);
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/egl/EGLConfigChooser.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/egl/EGLConfigChooser.java
new file mode 100644
index 0000000000..b6f467708f
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/egl/EGLConfigChooser.java
@@ -0,0 +1,293 @@
+package com.mapbox.mapboxsdk.maps.renderer.egl;
+
+import android.opengl.GLSurfaceView;
+import android.support.annotation.NonNull;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLDisplay;
+
+import timber.log.Timber;
+
+import static com.mapbox.mapboxsdk.utils.Compare.compare;
+import static javax.microedition.khronos.egl.EGL10.EGL_ALPHA_MASK_SIZE;
+import static javax.microedition.khronos.egl.EGL10.EGL_ALPHA_SIZE;
+import static javax.microedition.khronos.egl.EGL10.EGL_BLUE_SIZE;
+import static javax.microedition.khronos.egl.EGL10.EGL_BUFFER_SIZE;
+import static javax.microedition.khronos.egl.EGL10.EGL_COLOR_BUFFER_TYPE;
+import static javax.microedition.khronos.egl.EGL10.EGL_CONFIG_CAVEAT;
+import static javax.microedition.khronos.egl.EGL10.EGL_DEPTH_SIZE;
+import static javax.microedition.khronos.egl.EGL10.EGL_GREEN_SIZE;
+import static javax.microedition.khronos.egl.EGL10.EGL_NONE;
+import static javax.microedition.khronos.egl.EGL10.EGL_RED_SIZE;
+import static javax.microedition.khronos.egl.EGL10.EGL_RENDERABLE_TYPE;
+import static javax.microedition.khronos.egl.EGL10.EGL_RGB_BUFFER;
+import static javax.microedition.khronos.egl.EGL10.EGL_SAMPLES;
+import static javax.microedition.khronos.egl.EGL10.EGL_SAMPLE_BUFFERS;
+import static javax.microedition.khronos.egl.EGL10.EGL_STENCIL_SIZE;
+import static javax.microedition.khronos.egl.EGL10.EGL_SURFACE_TYPE;
+import static javax.microedition.khronos.egl.EGL10.EGL_WINDOW_BIT;
+
+/**
+ * Selects the right EGLConfig needed for `mapbox-gl-native`
+ */
+public class EGLConfigChooser implements GLSurfaceView.EGLConfigChooser {
+
+ /**
+ * Requires API level 17
+ *
+ * @see android.opengl.EGL14.EGL_CONFORMANT;
+ */
+ @SuppressWarnings("JavadocReference")
+ private static final int EGL_CONFORMANT = 0x3042;
+
+ /**
+ * Requires API level 17
+ *
+ * @see android.opengl.EGL14.EGL_OPENGL_ES2_BIT;
+ */
+ @SuppressWarnings("JavadocReference")
+ private static final int EGL_OPENGL_ES2_BIT = 0x0004;
+
+ @Override
+ public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
+ int[] configAttribs = getConfigAttributes();
+
+ // Determine number of possible configurations
+ int[] numConfigs = getNumberOfConfigurations(egl, display, configAttribs);
+ if (numConfigs[0] < 1) {
+ Timber.e("eglChooseConfig() returned no configs.");
+ throw new EGLConfigException("eglChooseConfig() failed");
+ }
+
+ // Get all possible configurations
+ EGLConfig[] possibleConfigurations = getPossibleConfigurations(egl, display, configAttribs, numConfigs);
+
+ // Choose best match
+ EGLConfig config = chooseBestMatchConfig(egl, display, possibleConfigurations);
+ if (config == null) {
+ Timber.e("No config chosen");
+ throw new EGLConfigException("No config chosen");
+ }
+
+ return config;
+ }
+
+ private int[] getNumberOfConfigurations(EGL10 egl, EGLDisplay display, int[] configAttributes) {
+ int[] numConfigs = new int[1];
+ if (!egl.eglChooseConfig(display, configAttributes, null, 0, numConfigs)) {
+ Timber.e("eglChooseConfig(NULL) returned error %d", egl.eglGetError());
+ throw new EGLConfigException("eglChooseConfig() failed");
+ }
+ return numConfigs;
+ }
+
+ private EGLConfig[] getPossibleConfigurations(EGL10 egl, EGLDisplay display,
+ int[] configAttributes, int[] numConfigs) {
+ EGLConfig[] configs = new EGLConfig[numConfigs[0]];
+ if (!egl.eglChooseConfig(display, configAttributes, configs, numConfigs[0], numConfigs)) {
+ Timber.e("eglChooseConfig() returned error %d", egl.eglGetError());
+ throw new EGLConfigException("eglChooseConfig() failed");
+ }
+ return configs;
+ }
+
+ // Quality
+ enum BufferFormat {
+ Format16Bit(3),
+ Format32BitNoAlpha(1),
+ Format32BitAlpha(2),
+ Format24Bit(0),
+ Unknown(4);
+
+ int value;
+
+ BufferFormat(int value) {
+ this.value = value;
+ }
+ }
+
+ enum DepthStencilFormat {
+ Format16Depth8Stencil(1),
+ Format24Depth8Stencil(0);
+
+ int value;
+
+ DepthStencilFormat(int value) {
+ this.value = value;
+ }
+ }
+
+ private EGLConfig chooseBestMatchConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs) {
+ class Config implements Comparable<Config> {
+ private final BufferFormat bufferFormat;
+ private final DepthStencilFormat depthStencilFormat;
+ private final boolean isNotConformant;
+ private final boolean isCaveat;
+ private final int index;
+ private final EGLConfig config;
+
+ public Config(BufferFormat bufferFormat, DepthStencilFormat depthStencilFormat,
+ boolean isNotConformant, boolean isCaveat, int index, EGLConfig config) {
+ this.bufferFormat = bufferFormat;
+ this.depthStencilFormat = depthStencilFormat;
+ this.isNotConformant = isNotConformant;
+ this.isCaveat = isCaveat;
+ this.index = index;
+ this.config = config;
+ }
+
+
+ @Override
+ public int compareTo(@NonNull Config other) {
+ int i = compare(bufferFormat.value, other.bufferFormat.value);
+ if (i != 0) {
+ return i;
+ }
+
+ i = compare(depthStencilFormat.value, other.depthStencilFormat.value);
+ if (i != 0) {
+ return i;
+ }
+
+ i = compare(isNotConformant, other.isNotConformant);
+ if (i != 0) {
+ return i;
+ }
+
+ i = compare(isCaveat, other.isCaveat);
+ if (i != 0) {
+ return i;
+ }
+
+ i = compare(index, other.index);
+ if (i != 0) {
+ return i;
+ }
+
+ return 0;
+ }
+ }
+
+ List<Config> matches = new ArrayList<>();
+
+ int i = 0;
+ for (EGLConfig config : configs) {
+ i++;
+
+ int caveat = getConfigAttr(egl, display, config, EGL_CONFIG_CAVEAT);
+ int conformant = getConfigAttr(egl, display, config, EGL_CONFORMANT);
+ int bits = getConfigAttr(egl, display, config, EGL_BUFFER_SIZE);
+ int red = getConfigAttr(egl, display, config, EGL_RED_SIZE);
+ int green = getConfigAttr(egl, display, config, EGL_GREEN_SIZE);
+ int blue = getConfigAttr(egl, display, config, EGL_BLUE_SIZE);
+ int alpha = getConfigAttr(egl, display, config, EGL_ALPHA_SIZE);
+ int alphaMask = getConfigAttr(egl, display, config, EGL_ALPHA_MASK_SIZE);
+ int depth = getConfigAttr(egl, display, config, EGL_DEPTH_SIZE);
+ int stencil = getConfigAttr(egl, display, config, EGL_STENCIL_SIZE);
+ int sampleBuffers = getConfigAttr(egl, display, config, EGL_SAMPLE_BUFFERS);
+ int samples = getConfigAttr(egl, display, config, EGL_SAMPLES);
+
+ boolean configOk = (depth == 24) || (depth == 16);
+ configOk &= stencil == 8;
+ configOk &= sampleBuffers == 0;
+ configOk &= samples == 0;
+
+ // Filter our configs first for depth, stencil and anti-aliasing
+ if (configOk) {
+ // Work out the config's buffer format
+ BufferFormat bufferFormat;
+ if ((bits == 16) && (red == 5) && (green == 6) && (blue == 5) && (alpha == 0)) {
+ bufferFormat = BufferFormat.Format16Bit;
+ } else if ((bits == 32) && (red == 8) && (green == 8) && (blue == 8) && (alpha == 0)) {
+ bufferFormat = BufferFormat.Format32BitNoAlpha;
+ } else if ((bits == 32) && (red == 8) && (green == 8) && (blue == 8) && (alpha == 8)) {
+ bufferFormat = BufferFormat.Format32BitAlpha;
+ } else if ((bits == 24) && (red == 8) && (green == 8) && (blue == 8) && (alpha == 0)) {
+ bufferFormat = BufferFormat.Format24Bit;
+ } else {
+ bufferFormat = BufferFormat.Unknown;
+ }
+
+ // Work out the config's depth stencil format
+ DepthStencilFormat depthStencilFormat;
+ if ((depth == 16) && (stencil == 8)) {
+ depthStencilFormat = DepthStencilFormat.Format16Depth8Stencil;
+ } else {
+ depthStencilFormat = DepthStencilFormat.Format24Depth8Stencil;
+ }
+
+ boolean isNotConformant = (conformant & EGL_OPENGL_ES2_BIT) != EGL_OPENGL_ES2_BIT;
+ boolean isCaveat = caveat != EGL_NONE;
+
+ // Ignore formats we don't recognise
+ if (bufferFormat != BufferFormat.Unknown) {
+ matches.add(new Config(bufferFormat, depthStencilFormat, isNotConformant, isCaveat, i, config));
+ }
+ }
+
+ }
+
+ // Sort
+ Collections.sort(matches);
+
+ if (matches.size() == 0) {
+ throw new EGLConfigException("No matching configurations after filtering");
+ }
+
+ Config bestMatch = matches.get(0);
+
+ if (bestMatch.isCaveat) {
+ Timber.w("Chosen config has a caveat.");
+ }
+
+ if (bestMatch.isNotConformant) {
+ Timber.w("Chosen config is not conformant.");
+ }
+
+ return bestMatch.config;
+ }
+
+ private int getConfigAttr(EGL10 egl, EGLDisplay display, EGLConfig config, int attributeName) {
+ int[] attributevalue = new int[1];
+ if (!egl.eglGetConfigAttrib(display, config, attributeName, attributevalue)) {
+ Timber.e("eglGetConfigAttrib(%d) returned error %d", attributeName, egl.eglGetError());
+ throw new EGLConfigException("eglGetConfigAttrib() failed");
+ }
+ return attributevalue[0];
+ }
+
+
+ private int[] getConfigAttributes() {
+ boolean emulator = inEmulator();
+ Timber.i("In emulator: %s", emulator);
+
+ // Get all configs at least RGB 565 with 16 depth and 8 stencil
+ return new int[] {
+ EGL_CONFIG_CAVEAT, EGL_NONE,
+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+ EGL_BUFFER_SIZE, 16,
+ EGL_RED_SIZE, 5,
+ EGL_GREEN_SIZE, 6,
+ EGL_BLUE_SIZE, 5,
+ EGL_ALPHA_SIZE, 0,
+ EGL_DEPTH_SIZE, 16,
+ EGL_STENCIL_SIZE, 8,
+ (emulator ? EGL_NONE : EGL_CONFORMANT), EGL_OPENGL_ES2_BIT,
+ (emulator ? EGL_NONE : EGL_COLOR_BUFFER_TYPE), EGL_RGB_BUFFER,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_NONE
+ };
+ }
+
+ /**
+ * Detect if we are in emulator.
+ */
+ private boolean inEmulator() {
+ return System.getProperty("ro.kernel.qemu") != null;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/egl/EGLConfigException.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/egl/EGLConfigException.java
new file mode 100644
index 0000000000..d5a1c9951f
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/egl/EGLConfigException.java
@@ -0,0 +1,21 @@
+package com.mapbox.mapboxsdk.maps.renderer.egl;
+
+/**
+ * Used for EGL configuration exceptions
+ */
+public class EGLConfigException extends RuntimeException {
+ public EGLConfigException() {
+ }
+
+ public EGLConfigException(String message) {
+ super(message);
+ }
+
+ public EGLConfigException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public EGLConfigException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/GLSurfaceViewMapRenderer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/GLSurfaceViewMapRenderer.java
new file mode 100644
index 0000000000..7bc56475c0
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/glsurfaceview/GLSurfaceViewMapRenderer.java
@@ -0,0 +1,81 @@
+package com.mapbox.mapboxsdk.maps.renderer.glsurfaceview;
+
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+
+import com.mapbox.mapboxsdk.maps.renderer.MapRenderer;
+import com.mapbox.mapboxsdk.maps.renderer.egl.EGLConfigChooser;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+import static android.opengl.GLSurfaceView.RENDERMODE_WHEN_DIRTY;
+
+/**
+ * The {@link GLSurfaceViewMapRenderer} encapsulates the GL thread and
+ * {@link GLSurfaceView} specifics to render the map.
+ *
+ * @see MapRenderer
+ */
+public class GLSurfaceViewMapRenderer extends MapRenderer implements GLSurfaceView.Renderer {
+
+ private final GLSurfaceView glSurfaceView;
+
+ public GLSurfaceViewMapRenderer(Context context, GLSurfaceView glSurfaceView, String localIdeographFontFamily) {
+ super(context, localIdeographFontFamily);
+ this.glSurfaceView = glSurfaceView;
+ glSurfaceView.setEGLContextClientVersion(2);
+ glSurfaceView.setEGLConfigChooser(new EGLConfigChooser());
+ glSurfaceView.setRenderer(this);
+ glSurfaceView.setRenderMode(RENDERMODE_WHEN_DIRTY);
+ }
+
+ @Override
+ public void onStop() {
+ glSurfaceView.onPause();
+ }
+
+ @Override
+ public void onStart() {
+ glSurfaceView.onResume();
+ }
+
+ @Override
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ super.onSurfaceCreated(gl, config);
+ }
+
+ @Override
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+ super.onSurfaceChanged(gl, width, height);
+ }
+
+ @Override
+ public void onDrawFrame(GL10 gl) {
+ super.onDrawFrame(gl);
+ }
+
+ /**
+ * May be called from any thread.
+ * <p>
+ * Called from the renderer frontend to schedule a render.
+ */
+ @Override
+ public void requestRender() {
+ glSurfaceView.requestRender();
+ }
+
+ /**
+ * May be called from any thread.
+ * <p>
+ * Schedules work to be performed on the MapRenderer thread.
+ *
+ * @param runnable the runnable to execute
+ */
+ @Override
+ public void queueEvent(Runnable runnable) {
+ glSurfaceView.queueEvent(runnable);
+ }
+
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewMapRenderer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewMapRenderer.java
new file mode 100644
index 0000000000..dcc95217ff
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewMapRenderer.java
@@ -0,0 +1,98 @@
+package com.mapbox.mapboxsdk.maps.renderer.textureview;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.view.TextureView;
+
+import com.mapbox.mapboxsdk.maps.renderer.MapRenderer;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+/**
+ * The {@link TextureViewMapRenderer} encapsulates the GL thread and
+ * {@link TextureView} specifics to render the map.
+ *
+ * @see MapRenderer
+ */
+public class TextureViewMapRenderer extends MapRenderer {
+ private TextureViewRenderThread renderThread;
+
+ /**
+ * Create a {@link MapRenderer} for the given {@link TextureView}
+ *
+ * @param context the current Context
+ * @param textureView the TextureView
+ */
+ public TextureViewMapRenderer(@NonNull Context context,
+ @NonNull TextureView textureView,
+ String localIdeographFontFamily) {
+ super(context, localIdeographFontFamily);
+ renderThread = new TextureViewRenderThread(textureView, this);
+ renderThread.start();
+ }
+
+ /**
+ * Overridden to provide package access
+ */
+ @Override
+ protected void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ super.onSurfaceCreated(gl, config);
+ }
+
+ /**
+ * Overridden to provide package access
+ */
+ @Override
+ protected void onSurfaceChanged(GL10 gl, int width, int height) {
+ super.onSurfaceChanged(gl, width, height);
+ }
+
+ /**
+ * Overridden to provide package access
+ */
+ @Override
+ protected void onDrawFrame(GL10 gl) {
+ super.onDrawFrame(gl);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void requestRender() {
+ renderThread.requestRender();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void queueEvent(Runnable runnable) {
+ renderThread.queueEvent(runnable);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onStop() {
+ renderThread.onPause();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onStart() {
+ renderThread.onResume();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void onDestroy() {
+ renderThread.onDestroy();
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java
new file mode 100644
index 0000000000..c34833e9ce
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java
@@ -0,0 +1,459 @@
+package com.mapbox.mapboxsdk.maps.renderer.textureview;
+
+import android.graphics.SurfaceTexture;
+import android.support.annotation.NonNull;
+import android.support.annotation.UiThread;
+import android.view.TextureView;
+
+import com.mapbox.mapboxsdk.maps.renderer.egl.EGLConfigChooser;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGL11;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.egl.EGLSurface;
+import javax.microedition.khronos.opengles.GL10;
+
+import timber.log.Timber;
+
+/**
+ * The render thread is responsible for managing the communication between the
+ * ui thread and the render thread it creates. Also, the EGL and GL contexts
+ * are managed from here.
+ */
+class TextureViewRenderThread extends Thread implements TextureView.SurfaceTextureListener {
+
+ private final TextureViewMapRenderer mapRenderer;
+ private final EGLHolder eglHolder;
+
+ // Lock used for synchronization
+ private final Object lock = new Object();
+
+ // Guarded by lock
+ private final ArrayList<Runnable> eventQueue = new ArrayList<>();
+ private SurfaceTexture surface;
+ private int width;
+ private int height;
+ private boolean requestRender;
+ private boolean sizeChanged;
+ private boolean paused;
+ private boolean destroyContext;
+ private boolean destroySurface;
+ private boolean shouldExit;
+ private boolean exited;
+
+ /**
+ * Create a render thread for the given TextureView / Maprenderer combination.
+ *
+ * @param textureView the TextureView
+ * @param mapRenderer the MapRenderer
+ */
+ @UiThread
+ TextureViewRenderThread(@NonNull TextureView textureView, @NonNull TextureViewMapRenderer mapRenderer) {
+ textureView.setSurfaceTextureListener(this);
+ this.mapRenderer = mapRenderer;
+ this.eglHolder = new EGLHolder(new WeakReference<>(textureView));
+ }
+
+ // SurfaceTextureListener methods
+
+ @UiThread
+ @Override
+ public void onSurfaceTextureAvailable(final SurfaceTexture surface, final int width, final int height) {
+ synchronized (lock) {
+ this.surface = surface;
+ this.width = width;
+ this.height = height;
+ this.requestRender = true;
+ lock.notifyAll();
+ }
+ }
+
+ @Override
+ @UiThread
+ public void onSurfaceTextureSizeChanged(SurfaceTexture surface, final int width, final int height) {
+ synchronized (lock) {
+ this.width = width;
+ this.height = height;
+ this.sizeChanged = true;
+ this.requestRender = true;
+ lock.notifyAll();
+ }
+ }
+
+ @Override
+ @UiThread
+ public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
+ synchronized (lock) {
+ this.surface = null;
+ this.destroySurface = true;
+ this.requestRender = false;
+ lock.notifyAll();
+ }
+ return true;
+ }
+
+ @Override
+ @UiThread
+ public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+ // Ignored
+ }
+
+ // MapRenderer delegate methods
+
+ /**
+ * May be called from any thread
+ */
+ void requestRender() {
+ synchronized (lock) {
+ requestRender = true;
+ lock.notifyAll();
+ }
+ }
+
+ /**
+ * May be called from any thread
+ */
+ void queueEvent(Runnable runnable) {
+ if (runnable == null) {
+ throw new IllegalArgumentException("runnable must not be null");
+ }
+ synchronized (lock) {
+ eventQueue.add(runnable);
+ lock.notifyAll();
+ }
+ }
+
+
+ @UiThread
+ void onPause() {
+ synchronized (lock) {
+ this.paused = true;
+ lock.notifyAll();
+ }
+ }
+
+ @UiThread
+ void onResume() {
+ synchronized (lock) {
+ this.paused = false;
+ lock.notifyAll();
+ }
+ }
+
+
+ @UiThread
+ void onDestroy() {
+ synchronized (lock) {
+ this.shouldExit = true;
+ lock.notifyAll();
+
+ // Wait for the thread to exit
+ while (!this.exited) {
+ try {
+ lock.wait();
+ } catch (InterruptedException ex) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+ }
+
+ // Thread implementation
+
+ @Override
+ public void run() {
+ try {
+
+ while (true) {
+ Runnable event = null;
+ boolean initializeEGL = false;
+ boolean recreateSurface = false;
+ int w = -1;
+ int h = -1;
+
+ // Guarded block
+ synchronized (lock) {
+ while (true) {
+
+ if (shouldExit) {
+ return;
+ }
+
+ // If any events are scheduled, pop one for processing
+ if (!eventQueue.isEmpty()) {
+ event = eventQueue.remove(0);
+ break;
+ }
+
+ if (destroySurface) {
+ eglHolder.destroySurface();
+ destroySurface = false;
+ break;
+ }
+
+ if (destroyContext) {
+ eglHolder.destroyContext();
+ destroyContext = false;
+ break;
+ }
+
+ if (surface != null && !paused && requestRender) {
+
+ w = width;
+ h = height;
+
+ // Initialize EGL if needed
+ if (eglHolder.eglContext == EGL10.EGL_NO_CONTEXT) {
+ initializeEGL = true;
+ break;
+ }
+
+ // (re-)Initialize EGL Surface if needed
+ if (eglHolder.eglSurface == EGL10.EGL_NO_SURFACE) {
+ recreateSurface = true;
+ break;
+ }
+
+ // Check if the size has changed
+ if (sizeChanged) {
+ recreateSurface = true;
+ sizeChanged = false;
+ break;
+ }
+
+ // Reset the request render flag now, so we can catch new requests
+ // while rendering
+ requestRender = false;
+
+ // Break the guarded loop and continue to process
+ break;
+ }
+
+
+ // Wait until needed
+ lock.wait();
+
+ } // end guarded while loop
+
+ } // end guarded block
+
+ // Run event, if any
+ if (event != null) {
+ event.run();
+ continue;
+ }
+
+ GL10 gl = eglHolder.createGL();
+
+ // Initialize EGL
+ if (initializeEGL) {
+ eglHolder.prepare();
+ if (!eglHolder.createSurface()) {
+ synchronized (lock) {
+ // Cleanup the surface if one could not be created
+ // and wait for another to be ready.
+ destroySurface = true;
+ }
+ continue;
+ }
+ mapRenderer.onSurfaceCreated(gl, eglHolder.eglConfig);
+ mapRenderer.onSurfaceChanged(gl, w, h);
+ continue;
+ }
+
+ // If the surface size has changed inform the map renderer.
+ if (recreateSurface) {
+ eglHolder.createSurface();
+ mapRenderer.onSurfaceChanged(gl, w, h);
+ continue;
+ }
+
+ // Don't continue without a surface
+ if (eglHolder.eglSurface == EGL10.EGL_NO_SURFACE) {
+ continue;
+ }
+
+ // Time to render a frame
+ mapRenderer.onDrawFrame(gl);
+
+ // Swap and check the result
+ int swapError = eglHolder.swap();
+ switch (swapError) {
+ case EGL10.EGL_SUCCESS:
+ break;
+ case EGL11.EGL_CONTEXT_LOST:
+ Timber.w("Context lost. Waiting for re-aquire");
+ synchronized (lock) {
+ surface = null;
+ destroySurface = true;
+ destroyContext = true;
+ }
+ break;
+ default:
+ Timber.w("eglSwapBuffer error: %s. Waiting or new surface", swapError);
+ // Probably lost the surface. Clear the current one and
+ // wait for a new one to be set
+ synchronized (lock) {
+ surface = null;
+ destroySurface = true;
+ }
+ }
+
+ }
+
+ } catch (InterruptedException err) {
+ // To be expected
+ } finally {
+ // Cleanup
+ eglHolder.cleanup();
+
+ // Signal we're done
+ synchronized (lock) {
+ this.exited = true;
+ lock.notifyAll();
+ }
+ }
+ }
+
+ /**
+ * Holds the EGL state and offers methods to mutate it.
+ */
+ private static class EGLHolder {
+ private static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+ private final WeakReference<TextureView> textureViewWeakRef;
+
+ private EGL10 egl;
+ private EGLConfig eglConfig;
+ private EGLDisplay eglDisplay = EGL10.EGL_NO_DISPLAY;
+ private EGLContext eglContext = EGL10.EGL_NO_CONTEXT;
+ private EGLSurface eglSurface = EGL10.EGL_NO_SURFACE;
+
+ EGLHolder(WeakReference<TextureView> textureViewWeakRef) {
+ this.textureViewWeakRef = textureViewWeakRef;
+ }
+
+ void prepare() {
+ this.egl = (EGL10) EGLContext.getEGL();
+
+ // Only re-initialize display when needed
+ if (eglDisplay == EGL10.EGL_NO_DISPLAY) {
+ this.eglDisplay = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+
+ if (eglDisplay == EGL10.EGL_NO_DISPLAY) {
+ throw new RuntimeException("eglGetDisplay failed");
+ }
+
+ int[] version = new int[2];
+ if (!egl.eglInitialize(eglDisplay, version)) {
+ throw new RuntimeException("eglInitialize failed");
+ }
+ }
+
+ if (textureViewWeakRef == null) {
+ // No texture view present
+ eglConfig = null;
+ eglContext = EGL10.EGL_NO_CONTEXT;
+ } else if (eglContext == EGL10.EGL_NO_CONTEXT) {
+ eglConfig = new EGLConfigChooser().chooseConfig(egl, eglDisplay);
+ int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE};
+ eglContext = egl.eglCreateContext(eglDisplay, eglConfig, EGL10.EGL_NO_CONTEXT, attrib_list);
+ }
+
+ if (eglContext == EGL10.EGL_NO_CONTEXT) {
+ throw new RuntimeException("createContext");
+ }
+ }
+
+ GL10 createGL() {
+ return (GL10) eglContext.getGL();
+ }
+
+ boolean createSurface() {
+ // The window size has changed, so we need to create a new surface.
+ destroySurface();
+
+ // Create an EGL surface we can render into.
+ TextureView view = textureViewWeakRef.get();
+ if (view != null) {
+ int[] surfaceAttribs = {EGL10.EGL_NONE};
+ eglSurface = egl.eglCreateWindowSurface(eglDisplay, eglConfig, view.getSurfaceTexture(), surfaceAttribs);
+ } else {
+ eglSurface = EGL10.EGL_NO_SURFACE;
+ }
+
+ if (eglSurface == null || eglSurface == EGL10.EGL_NO_SURFACE) {
+ int error = egl.eglGetError();
+ if (error == EGL10.EGL_BAD_NATIVE_WINDOW) {
+ Timber.e("createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
+ }
+ return false;
+ }
+
+ return makeCurrent();
+ }
+
+ boolean makeCurrent() {
+ if (!egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) {
+ // Could not make the context current, probably because the underlying
+ // SurfaceView surface has been destroyed.
+ Timber.w("eglMakeCurrent: %s", egl.eglGetError());
+ return false;
+ }
+
+ return true;
+ }
+
+ int swap() {
+ if (!egl.eglSwapBuffers(eglDisplay, eglSurface)) {
+ return egl.eglGetError();
+ }
+ return EGL10.EGL_SUCCESS;
+ }
+
+ private void destroySurface() {
+ if (eglSurface == EGL10.EGL_NO_SURFACE) {
+ return;
+ }
+
+ if (!egl.eglDestroySurface(eglDisplay, eglSurface)) {
+ Timber.w("Could not destroy egl surface. Display %s, Surface %s", eglDisplay, eglSurface);
+ }
+
+ eglSurface = EGL10.EGL_NO_SURFACE;
+ }
+
+ private void destroyContext() {
+ if (eglContext == EGL10.EGL_NO_CONTEXT) {
+ return;
+ }
+
+ if (!egl.eglDestroyContext(eglDisplay, eglContext)) {
+ Timber.w("Could not destroy egl context. Display %s, Context %s", eglDisplay, eglContext);
+ }
+
+ eglContext = EGL10.EGL_NO_CONTEXT;
+ }
+
+ private void terminate() {
+ if (eglDisplay == EGL10.EGL_NO_DISPLAY) {
+ return;
+ }
+
+ if (!egl.eglTerminate(eglDisplay)) {
+ Timber.w("Could not terminate egl. Display %s", eglDisplay);
+ }
+ eglDisplay = EGL10.EGL_NO_DISPLAY;
+ }
+
+ void cleanup() {
+ destroySurface();
+ destroyContext();
+ terminate();
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java
index 2b327409ae..1e604c9bef 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/CompassView.java
@@ -1,23 +1,18 @@
package com.mapbox.mapboxsdk.maps.widgets;
import android.content.Context;
-import android.graphics.PointF;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewPropertyAnimatorCompat;
import android.support.v4.view.ViewPropertyAnimatorListenerAdapter;
-import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.ImageView;
-import com.mapbox.mapboxsdk.maps.FocalPointChangeListener;
import com.mapbox.mapboxsdk.maps.MapboxMap;
-import java.lang.ref.WeakReference;
-
/**
* UI element overlaid on a map to show the map's bearing when it isn't true north (0.0). Tapping
* the compass resets the bearing to true north and hides the compass.
@@ -27,16 +22,17 @@ import java.lang.ref.WeakReference;
* use {@link com.mapbox.mapboxsdk.maps.UiSettings}.
* </p>
*/
-public final class CompassView extends AppCompatImageView implements Runnable, FocalPointChangeListener {
+public final class CompassView extends ImageView implements Runnable {
- private static final long TIME_WAIT_IDLE = 500;
+ public static final long TIME_WAIT_IDLE = 500;
+ public static final long TIME_MAP_NORTH_ANIMATION = 150;
private static final long TIME_FADE_ANIMATION = TIME_WAIT_IDLE;
- private static final long TIME_MAP_NORTH_ANIMATION = 150;
private float rotation = 0.0f;
private boolean fadeCompassViewFacingNorth = true;
private ViewPropertyAnimatorCompat fadeAnimator;
- private PointF focalPoint;
+ private MapboxMap.OnCompassAnimationListener compassAnimationListener;
+ private boolean isAnimating = false;
public CompassView(Context context) {
super(context);
@@ -62,9 +58,12 @@ public final class CompassView extends AppCompatImageView implements Runnable, F
setLayoutParams(lp);
}
- // TODO refactor MapboxMap and replace with interface
- public void setMapboxMap(@NonNull MapboxMap mapboxMap) {
- setOnClickListener(new CompassClickListener(mapboxMap, this));
+ public void injectCompassAnimationListener(@NonNull MapboxMap.OnCompassAnimationListener compassAnimationListener) {
+ this.compassAnimationListener = compassAnimationListener;
+ }
+
+ public void isAnimating(boolean isAnimating) {
+ this.isAnimating = isAnimating;
}
private void resetAnimation() {
@@ -97,11 +96,6 @@ public final class CompassView extends AppCompatImageView implements Runnable, F
}
}
- @Nullable
- PointF getFocalPoint() {
- return focalPoint;
- }
-
/**
* Updates the direction of the compass.
*
@@ -126,6 +120,7 @@ public final class CompassView extends AppCompatImageView implements Runnable, F
setVisibility(View.VISIBLE);
}
+ notifyCompassAnimationListenerWhenAnimating();
setRotation(rotation);
}
@@ -157,7 +152,8 @@ public final class CompassView extends AppCompatImageView implements Runnable, F
@Override
public void run() {
- if (isFacingNorth() && fadeCompassViewFacingNorth) {
+ if (isHidden()) {
+ compassAnimationListener.onCompassAnimationFinished();
resetAnimation();
setLayerType(View.LAYER_TYPE_HARDWARE, null);
fadeAnimator = ViewCompat.animate(CompassView.this).alpha(0.0f).setDuration(TIME_FADE_ANIMATION);
@@ -172,34 +168,9 @@ public final class CompassView extends AppCompatImageView implements Runnable, F
}
}
- @Override
- public void onFocalPointChanged(PointF pointF) {
- focalPoint = pointF;
- }
-
- static class CompassClickListener implements View.OnClickListener {
-
- private WeakReference<MapboxMap> mapboxMap;
- private WeakReference<CompassView> compassView;
-
- CompassClickListener(final MapboxMap mapboxMap, CompassView compassView) {
- this.mapboxMap = new WeakReference<>(mapboxMap);
- this.compassView = new WeakReference<>(compassView);
- }
-
- @Override
- public void onClick(View view) {
- final MapboxMap mapboxMap = this.mapboxMap.get();
- final CompassView compassView = this.compassView.get();
- if (mapboxMap != null && compassView != null) {
- PointF focalPoint = compassView.getFocalPoint();
- if (focalPoint != null) {
- mapboxMap.setFocalBearing(0, focalPoint.x, focalPoint.y, TIME_MAP_NORTH_ANIMATION);
- } else {
- mapboxMap.setFocalBearing(0, mapboxMap.getWidth() / 2, mapboxMap.getHeight() / 2, TIME_MAP_NORTH_ANIMATION);
- }
- compassView.postDelayed(compassView, TIME_WAIT_IDLE + TIME_MAP_NORTH_ANIMATION);
- }
+ private void notifyCompassAnimationListenerWhenAnimating() {
+ if (isAnimating) {
+ compassAnimationListener.onCompassAnimation();
}
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java
index f5ef46a5d3..aa7934ec1e 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java
@@ -1,6 +1,7 @@
package com.mapbox.mapboxsdk.maps.widgets;
import android.animation.ValueAnimator;
+import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Camera;
import android.graphics.Canvas;
@@ -26,6 +27,7 @@ import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
+import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.MyBearingTracking;
@@ -40,11 +42,21 @@ import com.mapbox.services.android.telemetry.location.LocationEnginePriority;
import java.lang.ref.WeakReference;
+import timber.log.Timber;
+
/**
* UI element overlaid on a map to show the user's location.
+ * <p>
+ * Use {@link MyLocationViewSettings} to manipulate the state of this view.
+ * </p>
+ *
+ * @deprecated use location layer plugin from
+ * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugins/locationlayer instead.
*/
+@Deprecated
public class MyLocationView extends View {
+ private static final int UNDEFINED_TINT_COLOR = -1;
private MyLocationBehavior myLocationBehavior;
private MapboxMap mapboxMap;
@@ -58,16 +70,18 @@ public class MyLocationView extends View {
private LatLng latLng;
private Location location;
- private LocationEngine locationSource;
+ private LocationEngine locationEngine;
private long locationUpdateTimestamp;
private float previousDirection;
private float accuracy;
private Paint accuracyPaint;
+ private float accuracyThreshold;
private ValueAnimator locationChangeAnimator;
private ValueAnimator accuracyAnimator;
private ValueAnimator directionAnimator;
+ private boolean locationChangeAnimationEnabled = true;
private ValueAnimator.AnimatorUpdateListener invalidateSelfOnUpdateListener =
new ValueAnimator.AnimatorUpdateListener() {
@@ -147,6 +161,17 @@ public class MyLocationView extends View {
compassListener = new CompassListener(context);
}
+ @Deprecated
+ public void init(LocationSource locationSource) {
+ this.locationEngine = locationSource;
+ }
+
+ /**
+ * Set the foreground drawable, for internal use only.
+ *
+ * @param defaultDrawable The drawable shown when showing this view
+ * @param bearingDrawable The drawable shown when tracking of bearing is enabled
+ */
public final void setForegroundDrawables(Drawable defaultDrawable, Drawable bearingDrawable) {
if (defaultDrawable == null) {
return;
@@ -175,20 +200,35 @@ public class MyLocationView extends View {
invalidateBounds();
}
+ /**
+ * Set the foreground drawable tint, for internal use only.
+ *
+ * @param color The color to tint the drawable with
+ */
public final void setForegroundDrawableTint(@ColorInt int color) {
- if (foregroundDrawable != null) {
- foregroundDrawable.mutate().setColorFilter(color, PorterDuff.Mode.SRC_IN);
- }
- if (foregroundBearingDrawable != null) {
- foregroundBearingDrawable.mutate().setColorFilter(color, PorterDuff.Mode.SRC_IN);
- }
+ applyDrawableTint(foregroundDrawable, color);
+ applyDrawableTint(foregroundBearingDrawable, color);
invalidate();
}
+ /**
+ * Set the shadow drawable, for internal use only.
+ *
+ * @param drawable The drawable shown as shadow
+ */
public final void setShadowDrawable(Drawable drawable) {
setShadowDrawable(drawable, 0, 0, 0, 0);
}
+ /**
+ * Set the shadow drawable with some additional offset.
+ *
+ * @param drawable The drawable shown as shadow
+ * @param left The left offset margin
+ * @param top The top offset margin
+ * @param right The right offset margin
+ * @param bottom The bottom offset margin
+ */
public final void setShadowDrawable(Drawable drawable, int left, int top, int right, int bottom) {
if (drawable != null) {
backgroundDrawable = drawable;
@@ -202,14 +242,24 @@ public class MyLocationView extends View {
invalidateBounds();
}
+ /**
+ * Set the shadow drawable tint color, for internal use only.
+ *
+ * @param color The tint color to apply
+ */
public final void setShadowDrawableTint(@ColorInt int color) {
if (backgroundDrawable == null) {
return;
}
- backgroundDrawable.mutate().setColorFilter(color, PorterDuff.Mode.SRC_IN);
+ applyDrawableTint(backgroundDrawable, color);
invalidate();
}
+ /**
+ * Set the accuracy tint color, for internal use only.
+ *
+ * @param color The tint color to apply
+ */
public final void setAccuracyTint(@ColorInt int color) {
int alpha = accuracyPaint.getAlpha();
accuracyPaint.setColor(color);
@@ -217,6 +267,11 @@ public class MyLocationView extends View {
invalidate();
}
+ /**
+ * Set the accuracy alpha value, for internal use only.
+ *
+ * @param alpha The alpha accuracy value to apply
+ */
public final void setAccuracyAlpha(@IntRange(from = 0, to = 255) int alpha) {
accuracyPaint.setAlpha(alpha);
invalidate();
@@ -297,15 +352,25 @@ public class MyLocationView extends View {
}
// draw foreground
- if (myBearingTrackingMode == MyBearingTracking.NONE || !compassListener.isSensorAvailable()) {
+ if (myBearingTrackingMode == MyBearingTracking.NONE) {
if (foregroundDrawable != null) {
foregroundDrawable.draw(canvas);
}
} else if (foregroundBearingDrawable != null && foregroundBounds != null) {
- foregroundBearingDrawable.draw(canvas);
+ if (myBearingTrackingMode == MyBearingTracking.GPS || compassListener.isSensorAvailable()) {
+ foregroundBearingDrawable.draw(canvas);
+ } else {
+ // We are tracking MyBearingTracking.COMPASS, but sensor is not available.
+ foregroundDrawable.draw(canvas);
+ }
}
}
+ /**
+ * Set the tilt value, for internal use only.
+ *
+ * @param tilt The tilt to apply
+ */
public void setTilt(@FloatRange(from = 0, to = 60.0f) double tilt) {
this.tilt = tilt;
if (myLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) {
@@ -314,6 +379,11 @@ public class MyLocationView extends View {
invalidate();
}
+ /**
+ * Set the bearing value, for internal use only.
+ *
+ * @param bearing The bearing to apply
+ */
public void setBearing(double bearing) {
this.bearing = bearing;
if (myLocationTrackingMode == MyLocationTracking.TRACKING_NONE) {
@@ -327,6 +397,11 @@ public class MyLocationView extends View {
}
}
+ /**
+ * Set the bearing and tilt from a camera position, for internal use only.
+ *
+ * @param position The camera position to extract bearing and tilt from
+ */
public void setCameraPosition(CameraPosition position) {
if (position != null) {
setBearing(position.bearing);
@@ -334,6 +409,9 @@ public class MyLocationView extends View {
}
}
+ /**
+ * Called when the hosting activity is starting, for internal use only.
+ */
public void onStart() {
if (myBearingTrackingMode == MyBearingTracking.COMPASS && compassListener.isSensorAvailable()) {
compassListener.onResume();
@@ -343,6 +421,9 @@ public class MyLocationView extends View {
}
}
+ /**
+ * Called when the hosting activity is stopping, for internal use only.
+ */
public void onStop() {
compassListener.onPause();
toggleGps(false);
@@ -368,12 +449,15 @@ public class MyLocationView extends View {
}
if (userLocationListener != null) {
- locationSource.removeLocationEngineListener(userLocationListener);
- locationSource = null;
+ locationEngine.removeLocationEngineListener(userLocationListener);
+ locationEngine = null;
userLocationListener = null;
}
}
+ /**
+ * Update current locationstate.
+ */
public void update() {
if (isEnabled()) {
myLocationBehavior.invalidate();
@@ -388,13 +472,33 @@ public class MyLocationView extends View {
this.projection = mapboxMap.getProjection();
}
+ /**
+ * Set the enabled state, for internal use only.
+ *
+ * @param enabled The value to set the state to
+ */
@Override
public void setEnabled(boolean enabled) {
+ setEnabled(enabled, false);
+ }
+
+ /**
+ * Set the enabled state, for internal use only.
+ *
+ * @param enabled The value to set the state to
+ * @param isCustomLocationEngine Flag handling for handling user provided custom location engine
+ */
+ public void setEnabled(boolean enabled, boolean isCustomLocationEngine) {
super.setEnabled(enabled);
setVisibility(enabled ? View.VISIBLE : View.INVISIBLE);
- toggleGps(enabled);
+ toggleGps(enabled, isCustomLocationEngine);
}
+ /**
+ * Save the view instance state, for internal use only.
+ *
+ * @return the marshaled representation of the view state
+ */
@Override
protected Parcelable onSaveInstanceState() {
Bundle bundle = new Bundle();
@@ -403,6 +507,11 @@ public class MyLocationView extends View {
return bundle;
}
+ /**
+ * Restore the view instance state, for internal use only.
+ *
+ * @param state the marshalled representation of the state to restore
+ */
@Override
public void onRestoreInstanceState(Parcelable state) {
if (state instanceof Bundle) {
@@ -413,45 +522,59 @@ public class MyLocationView extends View {
super.onRestoreInstanceState(state);
}
+ private void toggleGps(boolean enableGps) {
+ toggleGps(enableGps, mapboxMap != null && mapboxMap.getTrackingSettings().isCustomLocationSource());
+ }
+
/**
- * Enabled / Disable GPS location updates along with updating the UI
+ * Enabled / Disable GPS location updates along with updating the UI, for internal use only.
*
* @param enableGps true if GPS is to be enabled, false if GPS is to be disabled
*/
- private void toggleGps(boolean enableGps) {
- if (locationSource == null) {
- locationSource = LocationSource.getLocationEngine(this.getContext());
- }
-
+ private void toggleGps(boolean enableGps, boolean isCustomLocationEngine) {
if (enableGps) {
- // Set an initial location if one available
- Location lastLocation = locationSource.getLastLocation();
-
- if (lastLocation != null) {
- setLocation(lastLocation);
+ if (locationEngine == null) {
+ if (!isCustomLocationEngine) {
+ locationEngine = Mapbox.getLocationEngine();
+ } else {
+ return;
+ }
}
if (userLocationListener == null) {
- userLocationListener = new GpsLocationListener(this, locationSource);
+ userLocationListener = new GpsLocationListener(this, locationEngine);
}
- locationSource.addLocationEngineListener(userLocationListener);
- locationSource.activate();
+ locationEngine.addLocationEngineListener(userLocationListener);
+ locationEngine.setPriority(LocationEnginePriority.HIGH_ACCURACY);
+ locationEngine.activate();
} else {
+ if (locationEngine == null) {
+ return;
+ }
// Disable location and user dot
location = null;
- locationSource.removeLocationUpdates();
- locationSource.removeLocationEngineListener(userLocationListener);
- locationSource.deactivate();
+ locationEngine.removeLocationEngineListener(userLocationListener);
+ locationEngine.removeLocationUpdates();
+ locationEngine.deactivate();
+ restoreLocationEngine();
}
-
- locationSource.setPriority(LocationEnginePriority.HIGH_ACCURACY);
}
+ /**
+ * Get the current location.
+ *
+ * @return the current location
+ */
public Location getLocation() {
return location;
}
+ /**
+ * Set the current location, for internal use only.
+ *
+ * @param location The current location
+ */
public void setLocation(Location location) {
if (location == null) {
this.location = null;
@@ -460,8 +583,37 @@ public class MyLocationView extends View {
this.location = location;
myLocationBehavior.updateLatLng(location);
+
+ if (mapboxMap != null && myBearingTrackingMode == MyBearingTracking.GPS
+ && myLocationTrackingMode == MyLocationTracking.TRACKING_NONE) {
+ setBearing(mapboxMap.getCameraPosition().bearing);
+ }
+ }
+
+ /**
+ * Set location change animation enabled, for internal use only.
+ *
+ * @param locationChangeAnimationEnabled True if location changes are animated
+ */
+ public void setLocationChangeAnimationEnabled(boolean locationChangeAnimationEnabled) {
+ this.locationChangeAnimationEnabled = locationChangeAnimationEnabled;
}
+ /**
+ * Set accuracy circle threshold. Circle won't be displayed if accuracy is below set value.
+ * For internal use only.
+ *
+ * @param accuracyThreshold Value below which circle won't be displayed
+ */
+ public void setAccuracyThreshold(float accuracyThreshold) {
+ this.accuracyThreshold = accuracyThreshold;
+ }
+
+ /**
+ * Set the bearing tracking mode, for internal use only.
+ *
+ * @param myBearingTrackingMode The bearing tracking mode
+ */
public void setMyBearingTrackingMode(@MyBearingTracking.Mode int myBearingTrackingMode) {
this.myBearingTrackingMode = myBearingTrackingMode;
if (myBearingTrackingMode == MyBearingTracking.COMPASS && compassListener.isSensorAvailable()) {
@@ -478,6 +630,11 @@ public class MyLocationView extends View {
invalidate();
}
+ /**
+ * Set the location tracking mode, for internla use only.
+ *
+ * @param myLocationTrackingMode The location tracking mode
+ */
public void setMyLocationTrackingMode(@MyLocationTracking.Mode int myLocationTrackingMode) {
MyLocationBehaviorFactory factory = new MyLocationBehaviorFactory();
myLocationBehavior = factory.getBehavioralModel(myLocationTrackingMode);
@@ -485,8 +642,7 @@ public class MyLocationView extends View {
if (location != null) {
if (myLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) {
// center map directly
- mapboxMap.easeCamera(CameraUpdateFactory.newLatLng(new LatLng(location)), 0, false /*linear interpolator*/,
- null, true);
+ mapboxMap.moveCamera(CameraUpdateFactory.newLatLng(new LatLng(location)));
} else {
// do not use interpolated location from tracking mode
latLng = null;
@@ -498,17 +654,32 @@ public class MyLocationView extends View {
invalidate();
}
+ /**
+ * Get the location tracking mode, for internal use only.
+ *
+ * @return The location tracking mode
+ */
@MyLocationTracking.Mode
public int getMyLocationTrackingMode() {
return myLocationTrackingMode;
}
+ /**
+ * Get the bearing tracking mode, for internal use only.
+ *
+ * @return the bearing tracking mode
+ */
@MyBearingTracking.Mode
public int getMyBearingTrackingMode() {
return myBearingTrackingMode;
}
+ /**
+ * Set the compass bearing value, for internal use only.
+ *
+ * @param bearing The compas bearing value
+ */
private void setCompass(double bearing) {
setCompass(bearing, 0 /* no animation */);
}
@@ -536,14 +707,29 @@ public class MyLocationView extends View {
directionAnimator.start();
}
+ /**
+ * Get the center of this view in screen coordinates.
+ *
+ * @return the center of the view
+ */
public PointF getCenter() {
return new PointF(getCenterX(), getCenterY());
}
+ /**
+ * Get the x value of the center of this view.
+ *
+ * @return the x value of the center of the view
+ */
private float getCenterX() {
return (getX() + getMeasuredWidth()) / 2 + contentPaddingX - projectedX;
}
+ /**
+ * Get the y value of the center of this view.
+ *
+ * @return the y value of the center of the view
+ */
private float getCenterY() {
return (getY() + getMeasuredHeight()) / 2 + contentPaddingY - projectedY;
}
@@ -553,8 +739,41 @@ public class MyLocationView extends View {
contentPaddingY = (padding[1] - padding[3]) / 2;
}
- public void setLocationSource(LocationEngine locationSource) {
- this.locationSource = locationSource;
+ /**
+ * Set the location source from which location updates are received, for internal use only.
+ *
+ * @param locationEngine The location engine to receive updates from
+ */
+ public void setLocationSource(LocationEngine locationEngine) {
+ toggleGps(false);
+ this.locationEngine = locationEngine;
+ this.userLocationListener = null;
+ setEnabled(isEnabled(), locationEngine != null);
+ }
+
+ private void applyDrawableTint(Drawable drawable, @ColorInt int color) {
+ if (color == UNDEFINED_TINT_COLOR) {
+ removeTintColorFilter(drawable);
+ } else {
+ applyTintColorFilter(drawable, color);
+ }
+ }
+
+ private void removeTintColorFilter(Drawable drawable) {
+ if (drawable != null) {
+ drawable.mutate().setColorFilter(null);
+ }
+ }
+
+ private void applyTintColorFilter(Drawable drawable, @ColorInt int color) {
+ if (drawable != null) {
+ drawable.mutate().setColorFilter(color, PorterDuff.Mode.SRC_IN);
+ }
+ }
+
+ private void restoreLocationEngine() {
+ locationEngine.setPriority(LocationEnginePriority.LOW_POWER);
+ locationEngine.activate();
}
private static class GpsLocationListener implements LocationEngineListener {
@@ -567,13 +786,16 @@ public class MyLocationView extends View {
locationSource = new WeakReference<>(locationEngine);
}
+ @SuppressLint("MissingPermission")
@Override
public void onConnected() {
MyLocationView locationView = userLocationView.get();
- if (locationView != null) {
- LocationEngine locationEngine = locationSource.get();
- Location location = locationEngine.getLastLocation();
- locationView.setLocation(location);
+ LocationEngine locationEngine = locationSource.get();
+ if (locationView != null && locationEngine != null) {
+ Location lastKnownLocation = locationEngine.getLastLocation();
+ if (lastKnownLocation != null) {
+ locationView.setLocation(lastKnownLocation);
+ }
locationEngine.requestLocationUpdates();
}
}
@@ -597,9 +819,12 @@ public class MyLocationView extends View {
private final SensorManager sensorManager;
private Sensor rotationVectorSensor;
- float[] matrix = new float[9];
- float[] orientation = new float[3];
+ private float[] matrix = new float[9];
+ private float[] rotationVectorValue;
+ private float[] truncatedRotationVectorValue = new float[4];
+ private float[] orientation = new float[3];
+ private boolean reportMissingSensor = true;
// Compass data
private long compassUpdateNextTimestamp = 0;
@@ -617,6 +842,10 @@ public class MyLocationView extends View {
}
public boolean isSensorAvailable() {
+ if (rotationVectorSensor == null && reportMissingSensor) {
+ reportMissingSensor = false;
+ Timber.e("Sensor.TYPE_ROTATION_VECTOR is missing from this device. Unable to use MyBearingTracking.COMPASS.");
+ }
return rotationVectorSensor != null;
}
@@ -630,9 +859,8 @@ public class MyLocationView extends View {
}
if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
-
- // calculate the rotation matrix
- SensorManager.getRotationMatrixFromVector(matrix, event.values);
+ rotationVectorValue = getRotationVectorFromSensorEvent(event);
+ SensorManager.getRotationMatrixFromVector(matrix, rotationVectorValue);
SensorManager.getOrientation(matrix, orientation);
magneticHeading = (float) Math.toDegrees(SensorManager.getOrientation(matrix, orientation)[0]);
@@ -649,6 +877,28 @@ public class MyLocationView extends View {
}
}
+ /**
+ * Pulls out the rotation vector from a SensorEvent, with a maximum length
+ * vector of four elements to avoid potential compatibility issues.
+ *
+ * @param event the sensor event
+ * @return the events rotation vector, potentially truncated
+ */
+ @NonNull
+ float[] getRotationVectorFromSensorEvent(@NonNull SensorEvent event) {
+ if (event.values.length > 4) {
+ // On some Samsung devices SensorManager.getRotationMatrixFromVector
+ // appears to throw an exception if rotation vector has length > 4.
+ // For the purposes of this class the first 4 values of the
+ // rotation vector are sufficient (see crbug.com/335298 for details).
+ // Only affects Android 4.3
+ System.arraycopy(event.values, 0, truncatedRotationVectorValue, 0, 4);
+ return truncatedRotationVectorValue;
+ } else {
+ return event.values;
+ }
+ }
+
private void rotateCamera(float rotation) {
CameraPosition.Builder builder = new CameraPosition.Builder();
builder.bearing(rotation);
@@ -701,6 +951,12 @@ public class MyLocationView extends View {
private abstract class MyLocationBehavior {
+ MyLocationBehavior() {
+ if (latLng != null) {
+ locationUpdateTimestamp = SystemClock.elapsedRealtime();
+ }
+ }
+
void updateLatLng(@NonNull Location newLocation) {
location = newLocation;
}
@@ -719,10 +975,11 @@ public class MyLocationView extends View {
accuracyAnimator.end();
}
- accuracyAnimator = ValueAnimator.ofFloat(accuracy, location.getAccuracy());
+ float newAccuracy = location.getAccuracy() >= accuracyThreshold ? location.getAccuracy() : 0f;
+ accuracyAnimator = ValueAnimator.ofFloat(accuracy, newAccuracy);
accuracyAnimator.setDuration(750);
accuracyAnimator.start();
- accuracy = location.getAccuracy();
+ accuracy = newAccuracy;
}
abstract void invalidate();
@@ -767,9 +1024,13 @@ public class MyLocationView extends View {
// accuracy
updateAccuracy(location);
- // ease to new camera position with a linear interpolator
- mapboxMap.easeCamera(CameraUpdateFactory.newCameraPosition(builder.build()), animationDuration, false, null,
- true);
+ if (locationChangeAnimationEnabled && animationDuration > 0) {
+ // ease to new camera position with a linear interpolator
+ mapboxMap.easeCamera(CameraUpdateFactory.newCameraPosition(builder.build()), animationDuration, false, null,
+ true);
+ } else {
+ mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(builder.build()));
+ }
}
@Override
@@ -811,7 +1072,11 @@ public class MyLocationView extends View {
}
locationChangeAnimator = ValueAnimator.ofFloat(0.0f, 1.0f);
- locationChangeAnimator.setDuration(locationUpdateDuration);
+ if (locationChangeAnimationEnabled) {
+ locationChangeAnimator.setDuration(locationUpdateDuration);
+ } else {
+ locationChangeAnimator.setDuration(0);
+ }
locationChangeAnimator.addUpdateListener(new MarkerCoordinateAnimatorListener(this,
latLng, newLocation
));
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettings.java
index e9d823ebda..ec7c53e1d0 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettings.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettings.java
@@ -1,19 +1,26 @@
package com.mapbox.mapboxsdk.maps.widgets;
import android.graphics.drawable.Drawable;
+import android.os.Bundle;
import android.support.annotation.ColorInt;
import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
+import com.mapbox.mapboxsdk.camera.CameraPosition;
+import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.constants.MyLocationTracking;
import com.mapbox.mapboxsdk.maps.FocalPointChangeListener;
-import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
import com.mapbox.mapboxsdk.maps.Projection;
+import com.mapbox.mapboxsdk.utils.BitmapUtils;
/**
* Settings to configure the visual appearance of the MyLocationView.
+ *
+ * @deprecated use location layer plugin from
+ * https://github.com/mapbox/mapbox-plugins-android/tree/master/plugins/locationlayer instead.
*/
+@Deprecated
public class MyLocationViewSettings {
private Projection projection;
@@ -51,6 +58,7 @@ public class MyLocationViewSettings {
//
private int accuracyAlpha;
+ private float accuracyThreshold = 0f;
@ColorInt
private int accuracyTintColor;
@@ -77,6 +85,11 @@ public class MyLocationViewSettings {
this.focalPointChangeListener = focalPointChangedListener;
}
+ /**
+ * Initialise this with MapboxMapOptions.
+ *
+ * @param options the options to initialise this class from
+ */
public void initialise(@NonNull MapboxMapOptions options) {
CameraPosition position = options.getCamera();
if (position != null && !position.equals(CameraPosition.DEFAULT)) {
@@ -88,6 +101,57 @@ public class MyLocationViewSettings {
setBackgroundTintColor(options.getMyLocationBackgroundTintColor());
setAccuracyAlpha(options.getMyLocationAccuracyAlpha());
setAccuracyTintColor(options.getMyLocationAccuracyTintColor());
+ setAccuracyThreshold(options.getMyLocationAccuracyThreshold());
+ }
+
+ public void onSaveInstanceState(Bundle outState) {
+ outState.putBoolean(MapboxConstants.STATE_LOCATION_VIEW_ENABLED, isEnabled());
+ outState.putByteArray(
+ MapboxConstants.STATE_LOCATION_VIEW_FOREGROUND_DRAWABLE,
+ BitmapUtils.getByteArrayFromDrawable(getForegroundDrawable())
+ );
+ outState.putByteArray(
+ MapboxConstants.STATE_LOCATION_VIEW_FOREGROUND_BEARING_DRAWABLE,
+ BitmapUtils.getByteArrayFromDrawable(getForegroundBearingDrawable())
+ );
+ outState.putInt(MapboxConstants.STATE_LOCATION_VIEW_FOREGROUND_TINT_COLOR, getForegroundTintColor());
+ outState.putByteArray(
+ MapboxConstants.STATE_LOCATION_VIEW_BACKGROUND_DRAWABLE,
+ BitmapUtils.getByteArrayFromDrawable(getBackgroundDrawable())
+ );
+ outState.putIntArray(MapboxConstants.STATE_LOCATION_VIEW_BACKGROUND_OFFSET, getBackgroundOffset());
+ outState.putInt(MapboxConstants.STATE_LOCATION_VIEW_BACKGROUND_TINT_COLOR, getBackgroundTintColor());
+ outState.putInt(MapboxConstants.STATE_LOCATION_VIEW_ACCURACY_ALPHA, getAccuracyAlpha());
+ outState.putInt(MapboxConstants.STATE_LOCATION_VIEW_ACCURACY_TINT_COLOR, getAccuracyTintColor());
+ outState.putFloat(MapboxConstants.STATE_LOCATION_VIEW_ACCURACY_THRESHOLD, getAccuracyThreshold());
+ outState.putIntArray(MapboxConstants.STATE_LOCATION_VIEW_PADDING, getPadding());
+ }
+
+ public void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
+ setEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_LOCATION_VIEW_ENABLED));
+ setForegroundDrawable(
+ BitmapUtils.getDrawableFromByteArray(
+ myLocationView.getContext(),
+ savedInstanceState.getByteArray(MapboxConstants.STATE_LOCATION_VIEW_FOREGROUND_DRAWABLE)
+ ),
+ BitmapUtils.getDrawableFromByteArray(
+ myLocationView.getContext(),
+ savedInstanceState.getByteArray(MapboxConstants.STATE_LOCATION_VIEW_FOREGROUND_BEARING_DRAWABLE)
+ )
+ );
+ setForegroundTintColor(savedInstanceState.getInt(MapboxConstants.STATE_LOCATION_VIEW_FOREGROUND_TINT_COLOR));
+ setBackgroundDrawable(
+ BitmapUtils.getDrawableFromByteArray(
+ myLocationView.getContext(),
+ savedInstanceState.getByteArray(MapboxConstants.STATE_LOCATION_VIEW_BACKGROUND_DRAWABLE)
+ ),
+ savedInstanceState.getIntArray(MapboxConstants.STATE_LOCATION_VIEW_BACKGROUND_OFFSET)
+ );
+ setBackgroundTintColor(savedInstanceState.getInt(MapboxConstants.STATE_LOCATION_VIEW_BACKGROUND_TINT_COLOR));
+ setAccuracyAlpha(savedInstanceState.getInt(MapboxConstants.STATE_LOCATION_VIEW_ACCURACY_ALPHA));
+ setAccuracyTintColor(savedInstanceState.getInt(MapboxConstants.STATE_LOCATION_VIEW_ACCURACY_TINT_COLOR));
+ setAccuracyThreshold(savedInstanceState.getFloat(MapboxConstants.STATE_LOCATION_VIEW_ACCURACY_THRESHOLD));
+ setPadding(savedInstanceState.getIntArray(MapboxConstants.STATE_LOCATION_VIEW_PADDING));
}
/**
@@ -114,6 +178,7 @@ public class MyLocationViewSettings {
* <p>
* The foreground drawable is the image visible on screen
* </p>
+ * It's linked with the foreground tint color
*
* @param foregroundDrawable the drawable to show as foreground without bearing
* @param foregroundBearingDrawable the drawable to show as foreground when bearing is enabled
@@ -122,6 +187,7 @@ public class MyLocationViewSettings {
this.foregroundDrawable = foregroundDrawable;
this.foregroundBearingDrawable = foregroundBearingDrawable;
myLocationView.setForegroundDrawables(foregroundDrawable, foregroundBearingDrawable);
+ myLocationView.setForegroundDrawableTint(foregroundTintColor);
}
/**
@@ -148,7 +214,8 @@ public class MyLocationViewSettings {
* The color will tint both the foreground and the bearing foreground drawable.
* </p>
*
- * @param foregroundTintColor the color to tint the foreground drawable
+ * @param foregroundTintColor the color to tint the foreground drawable or -1 (undefined color) to remove the
+ * existing foreground tint color
*/
public void setForegroundTintColor(@ColorInt int foregroundTintColor) {
this.foregroundTintColor = foregroundTintColor;
@@ -169,6 +236,7 @@ public class MyLocationViewSettings {
* <p>
* Padding can be added to provide an offset to the background
* </p>
+ * It's linked with the background tint color
*
* @param backgroundDrawable the drawable to show as background
* @param padding the padding added to the background
@@ -181,6 +249,7 @@ public class MyLocationViewSettings {
} else {
myLocationView.setShadowDrawable(backgroundDrawable);
}
+ myLocationView.setShadowDrawableTint(backgroundTintColor);
}
/**
@@ -195,7 +264,8 @@ public class MyLocationViewSettings {
/**
* Set the background tint color.
*
- * @param backgroundTintColor the color to tint the background
+ * @param backgroundTintColor the color to tint the background drawable or -1 (undefined color) to remove the
+ * existing background tint color
*/
public void setBackgroundTintColor(@ColorInt int backgroundTintColor) {
this.backgroundTintColor = backgroundTintColor;
@@ -230,6 +300,10 @@ public class MyLocationViewSettings {
*/
public void setPadding(int left, int top, int right, int bottom) {
padding = new int[] {left, top, right, bottom};
+ setPadding(padding);
+ }
+
+ private void setPadding(int[] padding) {
myLocationView.setContentPadding(padding);
projection.invalidateContentPadding(padding);
invalidateFocalPointForTracking(myLocationView);
@@ -282,6 +356,25 @@ public class MyLocationViewSettings {
myLocationView.setAccuracyTint(accuracyTintColor);
}
+ /**
+ * Returns current accuracy threshold value (in meters).
+ *
+ * @return Value of accuracy threshold (in meters), below which circle won't be displayed
+ */
+ public float getAccuracyThreshold() {
+ return accuracyThreshold;
+ }
+
+ /**
+ * Set accuracy circle threshold. Circle won't be displayed if accuracy is below set value.
+ *
+ * @param accuracyThreshold Value of accuracy (in meters), below which circle won't be displayed
+ */
+ public void setAccuracyThreshold(float accuracyThreshold) {
+ this.accuracyThreshold = accuracyThreshold;
+ myLocationView.setAccuracyThreshold(accuracyThreshold);
+ }
+
public void setTilt(double tilt) {
myLocationView.setTilt(tilt);
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/ConnectivityReceiver.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/ConnectivityReceiver.java
index 7be56fa694..817dcdb438 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/ConnectivityReceiver.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/ConnectivityReceiver.java
@@ -1,5 +1,6 @@
package com.mapbox.mapboxsdk.net;
+import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -21,10 +22,14 @@ import timber.log.Timber;
* Not public api.
*/
public class ConnectivityReceiver extends BroadcastReceiver {
+ @SuppressLint("StaticFieldLeak")
private static ConnectivityReceiver INSTANCE;
/**
- * Get or create the singleton instance
+ * Get a single instance of ConnectivityReceiver.
+ *
+ * @param context the context to extract the application context from
+ * @return single instance of ConnectivityReceiver
*/
public static synchronized ConnectivityReceiver instance(Context context) {
if (INSTANCE == null) {
@@ -74,12 +79,12 @@ public class ConnectivityReceiver extends BroadcastReceiver {
}
/**
- * @see BroadcastReceiver#onReceive(Context, Intent)
+ * {@inheritDoc}
*/
@Override
public void onReceive(Context context, Intent intent) {
boolean connected = isConnected(context);
- Timber.v("Connected: " + connected);
+ Timber.v("Connected: %s", connected);
// Loop over listeners
for (ConnectivityListener listener : listeners) {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java
index ce498da8f5..6a2bf6b07b 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java
@@ -1,5 +1,6 @@
package com.mapbox.mapboxsdk.offline;
+import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Handler;
import android.os.Looper;
@@ -40,6 +41,7 @@ public class OfflineManager {
private Handler handler;
// This object is implemented as a singleton
+ @SuppressLint("StaticFieldLeak")
private static OfflineManager instance;
// The application context
@@ -90,11 +92,11 @@ public class OfflineManager {
*/
private OfflineManager(Context context) {
this.context = context.getApplicationContext();
- this.fileSource = FileSource.getInstance(context);
+ this.fileSource = FileSource.getInstance(this.context);
initialize(fileSource);
// Delete any existing previous ambient cache database
- deleteAmbientDatabase(context);
+ deleteAmbientDatabase(this.context);
}
private void deleteAmbientDatabase(final Context context) {
@@ -107,15 +109,21 @@ public class OfflineManager {
File file = new File(path);
if (file.exists()) {
file.delete();
- Timber.d("Old ambient cache database deleted to save space: " + path);
+ Timber.d("Old ambient cache database deleted to save space: %s", path);
}
} catch (Exception exception) {
- Timber.e("Failed to delete old ambient cache database: ", exception);
+ Timber.e(exception, "Failed to delete old ambient cache database: ");
}
}
}).start();
}
+ /**
+ * Get the single instance of offline manager.
+ *
+ * @param context the context used to host the offline manager
+ * @return the single instance of offline manager
+ */
public static synchronized OfflineManager getInstance(Context context) {
if (instance == null) {
instance = new OfflineManager(context);
@@ -141,8 +149,8 @@ public class OfflineManager {
*
* @param callback the callback to be invoked
*/
- public void listOfflineRegions(@NonNull
- final ListOfflineRegionsCallback callback) {
+ public void listOfflineRegions(@NonNull final ListOfflineRegionsCallback callback) {
+ fileSource.activate();
listOfflineRegions(fileSource, new ListOfflineRegionsCallback() {
@Override
@@ -150,6 +158,7 @@ public class OfflineManager {
getHandler().post(new Runnable() {
@Override
public void run() {
+ fileSource.deactivate();
callback.onList(offlineRegions);
}
});
@@ -160,6 +169,7 @@ public class OfflineManager {
getHandler().post(new Runnable() {
@Override
public void run() {
+ fileSource.deactivate();
callback.onError(error);
}
});
@@ -230,10 +240,12 @@ public class OfflineManager {
return LatLngBounds.world().contains(definition.getBounds());
}
- /*
- * Changing or bypassing this limit without permission from Mapbox is prohibited
- * by the Mapbox Terms of Service.
- */
+ /**
+ * Changing or bypassing this limit without permission from Mapbox is prohibited
+ * by the Mapbox Terms of Service.
+ *
+ * @param limit the new tile count limit.
+ */
public native void setOfflineMapboxTileCountLimit(long limit);
private native void initialize(FileSource fileSource);
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java
index fae53c2086..1b9a156352 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java
@@ -300,10 +300,19 @@ public class OfflineRegion {
/**
* Pause or resume downloading of regional resources.
+ * <p>
+ * After a download has been completed, you are required to reset the state of the region to STATE_INACTIVE.
+ * </p>
*
* @param state the download state
*/
public void setDownloadState(@DownloadState int state) {
+ if (state == STATE_ACTIVE) {
+ fileSource.activate();
+ } else {
+ fileSource.deactivate();
+ }
+
this.state = state;
setOfflineRegionDownloadState(state);
}
@@ -358,10 +367,10 @@ public class OfflineRegion {
*/
public void delete(@NonNull final OfflineRegionDeleteCallback callback) {
if (!isDeleted) {
+ isDeleted = true;
deleteOfflineRegion(new OfflineRegionDeleteCallback() {
@Override
public void onDelete() {
- isDeleted = true;
getHandler().post(new Runnable() {
@Override
public void run() {
@@ -376,6 +385,7 @@ public class OfflineRegion {
getHandler().post(new Runnable() {
@Override
public void run() {
+ isDeleted = false;
callback.onError(error);
}
});
@@ -394,6 +404,7 @@ public class OfflineRegion {
* After you call this method, you may not call any additional methods on this object.
* </p>
*
+ * @param bytes the metadata in bytes
* @param callback the callback to be invoked
*/
public void updateMetadata(@NonNull final byte[] bytes, @NonNull final OfflineRegionUpdateMetadataCallback callback) {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionStatus.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionStatus.java
index 9c3655fbec..0f4b81fc39 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionStatus.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegionStatus.java
@@ -7,6 +7,7 @@ package com.mapbox.mapboxsdk.offline;
* <p>
* Note that the total required size in bytes is not currently available. A
* future API release may provide an estimate of this number.
+ * </p>
*/
public class OfflineRegionStatus {
@@ -51,6 +52,7 @@ public class OfflineRegionStatus {
* Specifically, it is false during early phases of an offline download. Once
* style and tile sources have been downloaded, it is possible to calculate the
* precise number of required resources, at which point it is set to true.
+ * </p>
*/
private boolean requiredResourceCountIsPrecise = true;
@@ -73,37 +75,93 @@ public class OfflineRegionStatus {
}
/**
- * Is the region complete?
+ * Validates if the region download has completed
+ *
+ * @return true if download is complete, false if not
*/
public boolean isComplete() {
- return (completedResourceCount == requiredResourceCount);
+ return (completedResourceCount == requiredResourceCount) && downloadState == OfflineRegion.STATE_INACTIVE;
}
+ /**
+ * Returns the download state.
+ * <p>
+ * State is defined as
+ * </p>
+ * <ul>
+ * <li>{@link OfflineRegion#STATE_ACTIVE}</li>
+ * <li>{@link OfflineRegion#STATE_INACTIVE}</li>
+ * </ul>
+ *
+ * @return the download state.
+ */
@OfflineRegion.DownloadState
public int getDownloadState() {
return downloadState;
}
+ /**
+ * Get the number of resources (inclusive of tiles) that have been fully downloaded
+ * and are ready for offline access.
+ *
+ * @return the amount of resources that have finished downloading.
+ */
public long getCompletedResourceCount() {
return completedResourceCount;
}
+ /**
+ * The cumulative size, in bytes, of all resources (inclusive of tiles) that have
+ * been fully downloaded.
+ *
+ * @return the size of the resources that have finished downloading
+ */
public long getCompletedResourceSize() {
return completedResourceSize;
}
+ /**
+ * Get the number of tiles that have been fully downloaded and are ready for
+ * offline access.
+ *
+ * @return the completed tile count
+ */
public long getCompletedTileCount() {
return completedTileCount;
}
+ /**
+ * Get the cumulative size, in bytes, of all tiles that have been fully downloaded.
+ *
+ * @return the completed tile size
+ */
public long getCompletedTileSize() {
return completedTileSize;
}
+ /**
+ * Get the number of resources that are known to be required for this region. See the
+ * documentation for `requiredResourceCountIsPrecise` for an important caveat
+ * about this number.
+ *
+ * @return the amount of resources that are required
+ */
public long getRequiredResourceCount() {
return requiredResourceCount;
}
+ /**
+ * Returns when the value of requiredResourceCount is a precise
+ * count of the number of required resources, and false when it is merely a lower
+ * bound.
+ * <p>
+ * Specifically, it is false during early phases of an offline download. Once
+ * style and tile sources have been downloaded, it is possible to calculate the
+ * precise number of required resources, at which point it is set to true.
+ * </p>
+ *
+ * @return True if the required resource count is precise, false if not
+ */
public boolean isRequiredResourceCountPrecise() {
return requiredResourceCountIsPrecise;
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition.java
index f8ec0f3d39..2a32f0bdd6 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition.java
@@ -1,5 +1,9 @@
package com.mapbox.mapboxsdk.offline;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
/**
@@ -13,7 +17,7 @@ import com.mapbox.mapboxsdk.geometry.LatLngBounds;
* <p>
* pixelRatio must be ≥ 0 and should typically be 1.0 or 2.0.
*/
-public class OfflineTilePyramidRegionDefinition implements OfflineRegionDefinition {
+public class OfflineTilePyramidRegionDefinition implements OfflineRegionDefinition, Parcelable {
private String styleURL;
private LatLngBounds bounds;
@@ -22,7 +26,7 @@ public class OfflineTilePyramidRegionDefinition implements OfflineRegionDefiniti
private float pixelRatio;
/**
- * Constructor
+ * Constructor to create an OfflineTilePyramidDefinition from parameters.
*
* @param styleURL the style
* @param bounds the bounds
@@ -40,6 +44,22 @@ public class OfflineTilePyramidRegionDefinition implements OfflineRegionDefiniti
this.pixelRatio = pixelRatio;
}
+ /**
+ * Constructor to create an OfflineTilePyramidDefinition from a Parcel.
+ *
+ * @param parcel the parcel to create the OfflineTilePyramidDefinition from
+ */
+ public OfflineTilePyramidRegionDefinition(Parcel parcel) {
+ this.styleURL = parcel.readString();
+ this.bounds = new LatLngBounds.Builder()
+ .include(new LatLng(parcel.readDouble(), parcel.readDouble()))
+ .include(new LatLng(parcel.readDouble(), parcel.readDouble()))
+ .build();
+ this.minZoom = parcel.readDouble();
+ this.maxZoom = parcel.readDouble();
+ this.pixelRatio = parcel.readFloat();
+ }
+
/*
* Getters
*/
@@ -64,4 +84,34 @@ public class OfflineTilePyramidRegionDefinition implements OfflineRegionDefiniti
return pixelRatio;
}
+ /*
+ * Parceable
+ */
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(styleURL);
+ dest.writeDouble(bounds.getLatNorth());
+ dest.writeDouble(bounds.getLonEast());
+ dest.writeDouble(bounds.getLatSouth());
+ dest.writeDouble(bounds.getLonWest());
+ dest.writeDouble(minZoom);
+ dest.writeDouble(maxZoom);
+ dest.writeFloat(pixelRatio);
+ }
+
+ public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
+ public OfflineTilePyramidRegionDefinition createFromParcel(Parcel in) {
+ return new OfflineTilePyramidRegionDefinition(in);
+ }
+
+ public OfflineTilePyramidRegionDefinition[] newArray(int size) {
+ return new OfflineTilePyramidRegionDefinition[size];
+ }
+ };
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnaphotUtil.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnaphotUtil.java
new file mode 100644
index 0000000000..da86dc51fb
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnaphotUtil.java
@@ -0,0 +1,29 @@
+package com.mapbox.mapboxsdk.snapshotter;
+
+import android.graphics.BitmapFactory;
+
+class MapSnaphotUtil {
+
+ static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
+ // Raw height and width of image
+ final int height = options.outHeight;
+ final int width = options.outWidth;
+ int inSampleSize = 1;
+
+ if (height > reqHeight || width > reqWidth) {
+
+ final int halfHeight = height / 2;
+ final int halfWidth = width / 2;
+
+ // Calculate the largest inSampleSize value that is a power of 2 and keeps both
+ // height and width larger than the requested height and width.
+ while ((halfHeight / inSampleSize) >= reqHeight
+ && (halfWidth / inSampleSize) >= reqWidth) {
+ inSampleSize *= 2;
+ }
+ }
+ return inSampleSize;
+ }
+
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshot.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshot.java
new file mode 100644
index 0000000000..eb4f94c428
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshot.java
@@ -0,0 +1,63 @@
+package com.mapbox.mapboxsdk.snapshotter;
+
+import android.graphics.Bitmap;
+import android.graphics.PointF;
+
+import com.mapbox.mapboxsdk.geometry.LatLng;
+
+/**
+ * A completed snapshot.
+ *
+ * @see MapSnapshotter
+ */
+public class MapSnapshot {
+
+ private long nativePtr = 0;
+ private Bitmap bitmap;
+ private String[] attributions;
+ private boolean showLogo;
+
+ /**
+ * Created from native side
+ */
+ private MapSnapshot(long nativePtr, Bitmap bitmap, String[] attributions, boolean showLogo) {
+ this.nativePtr = nativePtr;
+ this.bitmap = bitmap;
+ this.attributions = attributions;
+ this.showLogo = showLogo;
+ }
+
+ /**
+ * @return the bitmap
+ */
+ public Bitmap getBitmap() {
+ return bitmap;
+ }
+
+ /**
+ * Calculate the point in pixels on the Image from geographical coordinates.
+ *
+ * @param latLng the geographical coordinates
+ * @return the point on the image
+ */
+ public native PointF pixelForLatLng(LatLng latLng);
+
+ /**
+ * @return The attributions for the sources of this snapshot.
+ */
+ protected String[] getAttributions() {
+ return attributions;
+ }
+
+ /**
+ * @return Flag indicating to show the Mapbox logo.
+ */
+ boolean isShowLogo() {
+ return showLogo;
+ }
+
+ // Unused, needed for peer binding
+ private native void initialize();
+
+ protected native void finalize();
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java
new file mode 100644
index 0000000000..5deedc3e63
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java
@@ -0,0 +1,367 @@
+package com.mapbox.mapboxsdk.snapshotter;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.UiThread;
+import android.util.DisplayMetrics;
+
+import com.mapbox.mapboxsdk.R;
+import com.mapbox.mapboxsdk.camera.CameraPosition;
+import com.mapbox.mapboxsdk.constants.Style;
+import com.mapbox.mapboxsdk.geometry.LatLngBounds;
+import com.mapbox.mapboxsdk.storage.FileSource;
+
+/**
+ * The map snapshotter creates a bitmap of the map, rendered
+ * off the UI thread. The snapshotter itself must be used on
+ * the UI thread (for access to the main looper)
+ */
+@UiThread
+public class MapSnapshotter {
+
+ /**
+ * Get notified on snapshot completion.
+ *
+ * @see MapSnapshotter#start(SnapshotReadyCallback, ErrorHandler)
+ */
+ public interface SnapshotReadyCallback {
+
+ /**
+ * Called when the snapshot is complete.
+ *
+ * @param snapshot the snapshot
+ */
+ void onSnapshotReady(MapSnapshot snapshot);
+
+ }
+
+ /**
+ * Can be used to get notified of errors
+ * in snapshot generation
+ *
+ * @see MapSnapshotter#start(SnapshotReadyCallback, ErrorHandler)
+ */
+ public interface ErrorHandler {
+
+ /**
+ * Called on error. Snapshotting will not
+ * continue
+ *
+ * @param error the error message
+ */
+ void onError(String error);
+ }
+
+ private static final int LOGO_MARGIN_DP = 4;
+
+ // Holds the pointer to JNI NativeMapView
+ private long nativePtr = 0;
+
+ private final Context context;
+ private SnapshotReadyCallback callback;
+ private ErrorHandler errorHandler;
+
+ /**
+ * MapSnapshotter options
+ */
+ public static class Options {
+ private int pixelRatio = 1;
+ private int width;
+ private int height;
+ private String styleUrl = Style.MAPBOX_STREETS;
+ private LatLngBounds region;
+ private CameraPosition cameraPosition;
+ private boolean showLogo = true;
+
+ /**
+ * @param width the width of the image
+ * @param height the height of the image
+ */
+ public Options(int width, int height) {
+ this.width = width;
+ this.height = height;
+ }
+
+ /**
+ * @param url The style URL to use
+ * @return the mutated {@link Options}
+ */
+ public Options withStyle(String url) {
+ this.styleUrl = url;
+ return this;
+ }
+
+ /**
+ * @param region the region to show in the snapshot.
+ * This is applied after the camera position
+ * @return the mutated {@link Options}
+ */
+ public Options withRegion(LatLngBounds region) {
+ this.region = region;
+ return this;
+ }
+
+ /**
+ * @param pixelRatio the pixel ratio to use (default: 1)
+ * @return the mutated {@link Options}
+ */
+ public Options withPixelRatio(int pixelRatio) {
+ this.pixelRatio = pixelRatio;
+ return this;
+ }
+
+ /**
+ * @param cameraPosition The camera position to use,
+ * the {@link CameraPosition#target} is overridden
+ * by region if set in conjunction.
+ * @return the mutated {@link Options}
+ */
+ public Options withCameraPosition(CameraPosition cameraPosition) {
+ this.cameraPosition = cameraPosition;
+ return this;
+ }
+
+ /**
+ * @param showLogo The flag indicating to show the Mapbox logo.
+ * @return the mutated {@link Options}
+ */
+ public Options withLogo(boolean showLogo) {
+ this.showLogo = showLogo;
+ return this;
+ }
+
+ /**
+ * @return the width of the image
+ */
+ public int getWidth() {
+ return width;
+ }
+
+ /**
+ * @return the height of the image
+ */
+ public int getHeight() {
+ return height;
+ }
+
+ /**
+ * @return the pixel ratio
+ */
+ public int getPixelRatio() {
+ return pixelRatio;
+ }
+
+ /**
+ * @return the region
+ */
+ @Nullable
+ public LatLngBounds getRegion() {
+ return region;
+ }
+
+ /**
+ * @return the style url
+ */
+ public String getStyleUrl() {
+ return styleUrl;
+ }
+
+ /**
+ * @return the camera position
+ */
+ @Nullable
+ public CameraPosition getCameraPosition() {
+ return cameraPosition;
+ }
+ }
+
+ /**
+ * Creates the Map snapshotter, but doesn't start rendering or
+ * loading yet.
+ *
+ * @param context the Context that is or contains the Application context
+ * @param options the options to use for the snapshot
+ */
+ public MapSnapshotter(@NonNull Context context, @NonNull Options options) {
+ this.context = context.getApplicationContext();
+ FileSource fileSource = FileSource.getInstance(context);
+ String programCacheDir = context.getCacheDir().getAbsolutePath();
+
+ nativeInitialize(this, fileSource, options.pixelRatio, options.width,
+ options.height, options.styleUrl, options.region, options.cameraPosition,
+ options.showLogo, programCacheDir);
+ }
+
+ /**
+ * Starts loading and rendering the snapshot. The callback will be fired
+ * on the calling thread.
+ *
+ * @param callback the callback to use when the snapshot is ready
+ */
+ public void start(@NonNull SnapshotReadyCallback callback) {
+ this.start(callback, null);
+ }
+
+ /**
+ * Starts loading and rendering the snapshot. The callbacks will be fired
+ * on the calling thread.
+ *
+ * @param callback the callback to use when the snapshot is ready
+ * @param errorHandler the error handler to use on snapshot errors
+ */
+ public void start(@NonNull SnapshotReadyCallback callback, ErrorHandler errorHandler) {
+ if (this.callback != null) {
+ throw new IllegalStateException("Snapshotter was already started");
+ }
+
+ this.callback = callback;
+ this.errorHandler = errorHandler;
+ nativeStart();
+ }
+
+ /**
+ * Updates the snapshotter with a new size
+ *
+ * @param width the width
+ * @param height the height
+ */
+ public native void setSize(int width, int height);
+
+ /**
+ * Updates the snapshotter with a new {@link CameraPosition}
+ *
+ * @param cameraPosition the camera position
+ */
+ public native void setCameraPosition(CameraPosition cameraPosition);
+
+ /**
+ * Updates the snapshotter with a new {@link LatLngBounds}
+ *
+ * @param region the region
+ */
+ public native void setRegion(LatLngBounds region);
+
+ /**
+ * Updates the snapshotter with a new style url
+ *
+ * @param styleUrl the style url
+ */
+ public native void setStyleUrl(String styleUrl);
+
+
+ /**
+ * Must be called in on the thread
+ * the object was created on.
+ */
+ public void cancel() {
+ reset();
+ nativeCancel();
+ }
+
+ /**
+ * Draw an overlay on the map snapshot.
+ *
+ * @param mapSnapshot the map snapshot to draw the overlay on
+ */
+ protected void addOverlay(MapSnapshot mapSnapshot) {
+ Bitmap original = mapSnapshot.getBitmap();
+ Canvas canvas = new Canvas(original);
+ addLogo(canvas, original);
+ }
+
+ /**
+ * Draw a logo on the canvas created from the map snapshot.
+ *
+ * @param canvas the canvas to draw the bitmap on
+ * @param original the map snapshot image
+ */
+ private void addLogo(Canvas canvas, Bitmap original) {
+ DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+ float margin = displayMetrics.density * LOGO_MARGIN_DP;
+ Bitmap logo = createScaledLogo(original);
+ canvas.drawBitmap(logo, margin, original.getHeight() - logo.getHeight() - margin, null);
+ }
+
+ /**
+ * Create a scaled logo for a map snapshot.
+ *
+ * @param snapshot the map snapshot where the logo should be placed on
+ * @return the scaled bitmap logo
+ */
+ private Bitmap createScaledLogo(Bitmap snapshot) {
+ Bitmap logo = BitmapFactory.decodeResource(context.getResources(), R.drawable.mapbox_logo_icon, null);
+ float scale = calculateLogoScale(snapshot, logo);
+ Matrix matrix = new Matrix();
+ matrix.postScale(scale, scale);
+ return Bitmap.createBitmap(logo, 0, 0, logo.getWidth(), logo.getHeight(), matrix, true);
+ }
+
+ /**
+ * Calculates the scale of the logo, only allow downscaling.
+ *
+ * @param snapshot the bitmap of the map snapshot
+ * @param logo the bitmap of the mapbox logo
+ * @return the scale value
+ */
+ private float calculateLogoScale(Bitmap snapshot, Bitmap logo) {
+ DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+ float widthRatio = displayMetrics.widthPixels / snapshot.getWidth();
+ float heightRatio = displayMetrics.heightPixels / snapshot.getHeight();
+ float prefWidth = logo.getWidth() / widthRatio;
+ float prefHeight = logo.getHeight() / heightRatio;
+ float calculatedScale = Math.min(prefWidth / logo.getWidth(), prefHeight / logo.getHeight()) * 2;
+ return calculatedScale < 1 ? calculatedScale : 1.0f;
+ }
+
+ /**
+ * Called by JNI peer when snapshot is ready.
+ * Always called on the origin (main) thread.
+ *
+ * @param snapshot the generated snapshot
+ */
+ protected void onSnapshotReady(MapSnapshot snapshot) {
+ if (callback != null) {
+ if (snapshot.isShowLogo()) {
+ addOverlay(snapshot);
+ }
+ callback.onSnapshotReady(snapshot);
+ reset();
+ }
+ }
+
+ /**
+ * Called by JNI peer when snapshot has failed.
+ * Always called on the origin (main) thread.
+ *
+ * @param reason the exception string
+ */
+ protected void onSnapshotFailed(String reason) {
+ if (errorHandler != null) {
+ errorHandler.onError(reason);
+ reset();
+ }
+ }
+
+ protected void reset() {
+ callback = null;
+ errorHandler = null;
+ }
+
+ protected native void nativeInitialize(MapSnapshotter mapSnapshotter,
+ FileSource fileSource, float pixelRatio,
+ int width, int height, String styleUrl,
+ LatLngBounds region, CameraPosition position,
+ boolean showLogo, String programCacheDir);
+
+ protected native void nativeStart();
+
+ protected native void nativeCancel();
+
+ @Override
+ protected native void finalize() throws Throwable;
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java
index 06676d76a1..f0cb8d973a 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java
@@ -3,13 +3,11 @@ package com.mapbox.mapboxsdk.storage;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.res.AssetManager;
import android.os.Environment;
import android.support.annotation.NonNull;
-import android.content.res.AssetManager;
-
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
-
import timber.log.Timber;
/**
@@ -28,8 +26,9 @@ public class FileSource {
/**
* Called whenever a URL needs to be transformed.
*
- * @param kind The kind of URL to be transformed.
- * @return A URL that will now be downloaded.
+ * @param kind the kind of URL to be transformed.
+ * @param url the URL to be transformed
+ * @return a URL that will now be downloaded.
*/
String onURL(@Resource.Kind int kind, String url);
@@ -38,6 +37,12 @@ public class FileSource {
// File source instance is kept alive after initialization
private static FileSource INSTANCE;
+ /**
+ * Get the single instance of FileSource.
+ *
+ * @param context the context to derive the cache path from
+ * @return the single instance of FileSource
+ */
public static synchronized FileSource getInstance(Context context) {
if (INSTANCE == null) {
String cachePath = getCachePath(context);
@@ -47,6 +52,12 @@ public class FileSource {
return INSTANCE;
}
+ /**
+ * Get the cache path for a context.
+ *
+ * @param context the context to derive the cache path from
+ * @return the cache path
+ */
public static String getCachePath(Context context) {
// Default value
boolean setStorageExternal = MapboxConstants.DEFAULT_SET_STORAGE_EXTERNAL;
@@ -59,9 +70,9 @@ public class FileSource {
MapboxConstants.KEY_META_DATA_SET_STORAGE_EXTERNAL,
MapboxConstants.DEFAULT_SET_STORAGE_EXTERNAL);
} catch (PackageManager.NameNotFoundException exception) {
- Timber.e("Failed to read the package metadata: ", exception);
+ Timber.e(exception, "Failed to read the package metadata: ");
} catch (Exception exception) {
- Timber.e("Failed to read the storage key: ", exception);
+ Timber.e(exception, "Failed to read the storage key: ");
}
String cachePath = null;
@@ -70,7 +81,7 @@ public class FileSource {
// Try getting the external storage path
cachePath = context.getExternalFilesDir(null).getAbsolutePath();
} catch (NullPointerException exception) {
- Timber.e("Failed to obtain the external storage path: ", exception);
+ Timber.e(exception, "Failed to obtain the external storage path: ");
}
}
@@ -111,6 +122,10 @@ public class FileSource {
initialize(Mapbox.getAccessToken(), cachePath, assetManager);
}
+ public native void activate();
+
+ public native void deactivate();
+
public native void setAccessToken(@NonNull String accessToken);
public native String getAccessToken();
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java
new file mode 100644
index 0000000000..4d09fcaac6
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java
@@ -0,0 +1,1761 @@
+package com.mapbox.mapboxsdk.style.expressions;
+
+import android.support.annotation.ColorInt;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.Size;
+
+import com.mapbox.mapboxsdk.style.layers.PropertyFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The value for any layout property, paint property, or filter may be specified as an expression.
+ * An expression defines a formula for computing the value of the property using the operators described below.
+ * The set of expression operators provided by Mapbox GL includes:
+ * <p>
+ * <ul>
+ * <li>Element</li>
+ * <li>Mathematical operators for performing arithmetic and other operations on numeric values</li>
+ * <li>Logical operators for manipulating boolean values and making conditional decisions</li>
+ * <li>String operators for manipulating strings</li>
+ * <li>Data operators, providing access to the properties of source features</li>
+ * <li>Camera operators, providing access to the parameters defining the current map view</li>
+ * </ul>
+ * </p>
+ * <p>
+ * Expressions are represented as JSON arrays.
+ * The first element of an expression array is a string naming the expression operator,
+ * e.g. "*"or "case". Subsequent elements (if any) are the arguments to the expression.
+ * Each argument is either a literal value (a string, number, boolean, or null), or another expression array.
+ * </p>
+ * <p>
+ * Data expression: a data expression is any expression that access feature data -- that is,
+ * any expression that uses one of the data operators:get,has,id,geometry-type, or properties.
+ * Data expressions allow a feature's properties to determine its appearance.
+ * They can be used to differentiate features within the same layer and to create data visualizations.
+ * </p>
+ * <p>
+ * Camera expression: a camera expression is any expression that uses the zoom operator.
+ * Such expressions allow the the appearance of a layer to change with the map's zoom level.
+ * Camera expressions can be used to create the appearance of depth and to control data density.
+ * </p>
+ * <p>
+ * Composition: a single expression may use a mix of data operators, camera operators, and other operators.
+ * Such composite expressions allows a layer's appearance to be determined by
+ * a combination of the zoom level and individual feature properties.
+ * </p>
+ *
+ * @param <T> the type of the expression
+ */
+public class Expression<T> {
+
+ private final String operator;
+ private final Expression[] arguments;
+
+ /**
+ * Creates an empty expression for expression literals
+ */
+ Expression() {
+ operator = null;
+ arguments = null;
+ }
+
+ /**
+ * Creates an expression from its operator and varargs expressions.
+ *
+ * @param operator the expression operator
+ * @param arguments expressions input
+ */
+ public Expression(@NonNull String operator, @Nullable Expression... arguments) {
+ this.operator = operator;
+ this.arguments = arguments;
+ }
+
+ /**
+ * Converts the expression to Object array representation.
+ * <p>
+ * The output will later be converted to a JSON Object array.
+ * </p>
+ *
+ * @return the converted object array expression
+ */
+ @NonNull
+ public Object[] toArray() {
+ List<Object> array = new ArrayList<>();
+ array.add(operator);
+ if (arguments != null) {
+ for (Expression argument : arguments) {
+ if (argument instanceof Expression.ExpressionLiteral) {
+ array.add(toValue((ExpressionLiteral) argument));
+ } else {
+ array.add(argument.toArray());
+ }
+ }
+ }
+ return array.toArray();
+ }
+
+ /**
+ * Converts the expression value to an Object.
+ *
+ * @param expressionValue the expression value to convert
+ * @return the converted object expression
+ */
+ private Object toValue(ExpressionLiteral expressionValue) {
+ Object value = expressionValue.toValue();
+ if (value instanceof Expression.Color) {
+ return ((Expression.Color) value).convertColor();
+ } else if (value instanceof Expression.ExpressionLiteral) {
+ return toValue((ExpressionLiteral) value);
+ } else if (value instanceof Expression) {
+ return ((Expression) value).toArray();
+ }
+ return value;
+ }
+
+ /**
+ * ExpressionLiteral wraps an object to be used as a literal in an expression.
+ * <p>
+ * ExpressionLiteral is created with {@link #literal(Number)}, {@link #literal(boolean)},
+ * {@link #literal(String)} and {@link #literal(Object)}.
+ * </p>
+ *
+ * @param <T>
+ */
+ private static class ExpressionLiteral<T> extends Expression<T> {
+
+ protected T object;
+
+ /**
+ * Create an ExpressionValue wrapper.
+ *
+ * @param object the object to be wrapped
+ */
+ ExpressionLiteral(@NonNull T object) {
+ this.object = object;
+ }
+
+ /**
+ * Get the wrapped object.
+ *
+ * @return the wrapped object
+ */
+ Object toValue() {
+ return object;
+ }
+ }
+
+ //
+ // Types
+ //
+
+ /**
+ * Expression interpolator type.
+ * <p>
+ * Is used for first parameter of {@link #interpolate(Expression, Expression, Stop...)}.
+ * </p>
+ */
+ private static class Interpolator {
+ }
+
+ /**
+ * Expression color type.
+ */
+ public static class Color {
+
+ private int color;
+
+ /**
+ * Creates a color color type from a color int.
+ *
+ * @param color the int color
+ */
+ public Color(@ColorInt int color) {
+ this.color = color;
+ }
+
+ /**
+ * Converts the int color to rgba(d, d, d, d) string representation
+ *
+ * @return
+ */
+ public String convertColor() {
+ return PropertyFactory.colorToRgbaString(color);
+ }
+ }
+
+ /**
+ * Expression array type.
+ */
+ public static class Array {
+ }
+
+ /**
+ * Expression stop type.
+ * <p>
+ * Can be used for {@link #stop(Object, Object)} as part of varargs parameter in
+ * {@link #step(Number, Expression, Stop...)} or {@link #interpolate(Expression, Expression, Stop...)}.
+ * </p>
+ */
+ public static class Stop {
+
+ private Object value;
+ private Object output;
+
+ public Stop(Object value, Object output) {
+ this.value = value;
+ this.output = output;
+ }
+ }
+
+ //
+ // Literals
+ //
+
+ /**
+ * Create a literal number expression.
+ *
+ * @param number the number
+ * @return the expression
+ */
+ public static Expression<Number> literal(@NonNull Number number) {
+ return new ExpressionLiteral<>(number);
+ }
+
+ /**
+ * Create a literal string expression.
+ *
+ * @param string the string
+ * @return the expression
+ */
+ public static Expression<String> literal(@NonNull String string) {
+ return new ExpressionLiteral<>(string);
+ }
+
+ /**
+ * Create a literal boolean expression.
+ *
+ * @param bool the boolean
+ * @return the expression
+ */
+ public static Expression<Boolean> literal(boolean bool) {
+ return new ExpressionLiteral<>(bool);
+ }
+
+ /**
+ * Create a literal object expression
+ *
+ * @param object the object
+ * @return the expression
+ */
+ public static Expression<Object> literal(@NonNull Object object) {
+ return new ExpressionLiteral<>(object);
+ }
+
+ //
+ // Color
+ //
+
+ /**
+ * Expression literal utility method to convert a color int to an color expression
+ *
+ * @param color the int color
+ * @return the color expression
+ */
+ public static Expression<Color> color(@ColorInt int color) {
+ return new ExpressionLiteral<>(new Color(color));
+ }
+
+ /**
+ * Creates a color value from red, green, and blue components, which must range between 0 and 255,
+ * and an alpha component of 1.
+ * <p>
+ * If any component is out of range, the expression is an error.
+ * </p>
+ *
+ * @param red red color expression
+ * @param green green color expression
+ * @param blue blue color expression
+ * @return expression
+ */
+ public static Expression<Color> rgb(@NonNull Expression<Number> red, @NonNull Expression<Number> green,
+ @NonNull Expression<Number> blue) {
+ return new Expression<>("rgb", red, green, blue);
+ }
+
+ /**
+ * Creates a color value from red, green, and blue components, which must range between 0 and 255,
+ * and an alpha component of 1.
+ * <p>
+ * If any component is out of range, the expression is an error.
+ * </p>
+ *
+ * @param red red color value
+ * @param green green color value
+ * @param blue blue color value
+ * @return expression
+ */
+ public static Expression<Color> rgb(@NonNull Number red, @NonNull Number green, @NonNull Number blue) {
+ return rgb(literal(red), literal(green), literal(blue));
+ }
+
+ /**
+ * Creates a color value from red, green, blue components, which must range between 0 and 255,
+ * and an alpha component which must range between 0 and 1.
+ * <p>
+ * If any component is out of range, the expression is an error.
+ * </p>
+ *
+ * @param red red color value
+ * @param green green color value
+ * @param blue blue color value
+ * @param alpha alpha color value
+ * @return expression
+ */
+ public static Expression<Color> rgba(@NonNull Expression<Number> red, @NonNull Expression<Number> green,
+ @NonNull Expression<Number> blue, @NonNull Expression<Number> alpha) {
+ return new Expression<>("rgba", red, green, blue, alpha);
+ }
+
+ /**
+ * Creates a color value from red, green, blue components, which must range between 0 and 255,
+ * and an alpha component which must range between 0 and 1.
+ * <p>
+ * If any component is out of range, the expression is an error.
+ * </p>
+ *
+ * @param red red color value
+ * @param green green color value
+ * @param blue blue color value
+ * @param alpha alpha color value
+ * @return expression
+ */
+ public static Expression<Color> rgba(@NonNull Number red, @NonNull Number green, @NonNull Number blue, @NonNull Number alpha) {
+ return rgba(literal(red), literal(green), literal(blue), literal(alpha));
+ }
+
+ /**
+ * Returns a four-element array containing the input color's red, green, blue, and alpha components, in that order.
+ *
+ * @param expression an expression to convert to a color
+ * @return expression
+ */
+ public static Expression<Array> toRgba(@NonNull Expression<Color> expression) {
+ return new Expression<>("to-rgba", expression);
+ }
+
+ //
+ // Decision
+ //
+
+ /**
+ * Returns true if the input values are equal, false otherwise.
+ * The inputs must be numbers, strings, or booleans, and both of the same type.
+ *
+ * @param compareOne the first expression
+ * @param compareTwo the second expression
+ * @return expression
+ */
+ public static Expression<Boolean> eq(@NonNull Expression compareOne, @NonNull Expression compareTwo) {
+ return new Expression<>("==", compareOne, compareTwo);
+ }
+
+ /**
+ * Returns true if the input values are equal, false otherwise.
+ *
+ * @param compareOne the first boolean
+ * @param compareTwo the second boolean
+ * @return expression
+ */
+ public static Expression<Boolean> eq(boolean compareOne, boolean compareTwo) {
+ return eq(literal(compareOne), literal(compareTwo));
+ }
+
+ /**
+ * Returns true if the input values are equal, false otherwise.
+ *
+ * @param compareOne the first number
+ * @param compareTwo the second number
+ * @return expression
+ */
+ public static Expression<Boolean> eq(@NonNull String compareOne, @NonNull String compareTwo) {
+ return eq(literal(compareOne), literal(compareTwo));
+ }
+
+ /**
+ * Returns true if the input values are equal, false otherwise.
+ *
+ * @param compareOne the first number
+ * @param compareTwo the second number
+ * @return expression
+ */
+ public static Expression<Boolean> eq(@NonNull Number compareOne, @NonNull Number compareTwo) {
+ return eq(literal(compareOne), literal(compareTwo));
+ }
+
+ /**
+ * Returns true if the input values are not equal, false otherwise.
+ * The inputs must be numbers, strings, or booleans, and both of the same type.
+ *
+ * @param compareOne the first expression
+ * @param compareTwo the second expression
+ * @return expression
+ */
+ public static Expression<Boolean> neq(@NonNull Expression compareOne, @NonNull Expression compareTwo) {
+ return new Expression<>("!=", compareOne, compareTwo);
+ }
+
+ /**
+ * Returns true if the input values are equal, false otherwise.
+ *
+ * @param compareOne the first boolean
+ * @param compareTwo the second boolean
+ * @return expression
+ */
+ public static Expression<Boolean> neq(boolean compareOne, boolean compareTwo) {
+ return new Expression<>("!=", literal(compareOne), literal(compareTwo));
+ }
+
+ /**
+ * Returns `true` if the input values are not equal, `false` otherwise.
+ *
+ * @param compareOne the first string
+ * @param compareTwo the second string
+ * @return expression
+ */
+ public static Expression<Boolean> neq(@NonNull String compareOne, @NonNull String compareTwo) {
+ return new Expression<>("!=", literal(compareOne), literal(compareTwo));
+ }
+
+ /**
+ * Returns `true` if the input values are not equal, `false` otherwise.
+ *
+ * @param compareOne the first number
+ * @param compareTwo the second number
+ * @return expression
+ */
+ public static Expression<Boolean> neq(@NonNull Number compareOne, @NonNull Number compareTwo) {
+ return new Expression<>("!=", literal(compareOne), literal(compareTwo));
+ }
+
+ /**
+ * Returns true if the first input is strictly greater than the second, false otherwise.
+ * The inputs must be numbers or strings, and both of the same type.
+ *
+ * @param compareOne the first expression
+ * @param compareTwo the second expression
+ * @return expression
+ */
+ public static Expression<Boolean> gt(@NonNull Expression compareOne, @NonNull Expression compareTwo) {
+ return new Expression<>(">", compareOne, compareTwo);
+ }
+
+ /**
+ * Returns true if the first input is strictly greater than the second, false otherwise.
+ *
+ * @param compareOne the first number
+ * @param compareTwo the second number
+ * @return expression
+ */
+ public static Expression<Boolean> gt(@NonNull Number compareOne, @NonNull Number compareTwo) {
+ return new Expression<>(">", literal(compareOne), literal(compareTwo));
+ }
+
+ /**
+ * Returns true if the first input is strictly greater than the second, false otherwise.
+ *
+ * @param compareOne the first string
+ * @param compareTwo the second string
+ * @return expression
+ */
+ public static Expression<Boolean> gt(@NonNull String compareOne, @NonNull String compareTwo) {
+ return new Expression<>(">", literal(compareOne), literal(compareTwo));
+ }
+
+ /**
+ * Returns true if the first input is strictly less than the second, false otherwise.
+ * The inputs must be numbers or strings, and both of the same type.
+ *
+ * @param compareOne the first number
+ * @param compareTwo the second number
+ * @return expression
+ */
+ public static Expression<Boolean> lt(@NonNull Expression compareOne, @NonNull Expression compareTwo) {
+ return new Expression<>("<", compareOne, compareTwo);
+ }
+
+ /**
+ * Returns true if the first input is strictly less than the second, false otherwise.
+ *
+ * @param compareOne the first number
+ * @param compareTwo the second number
+ * @return expression
+ */
+ public static Expression<Boolean> lt(@NonNull Number compareOne, @NonNull Number compareTwo) {
+ return new Expression<>("<", literal(compareOne), literal(compareTwo));
+ }
+
+ /**
+ * Returns true if the first input is strictly less than the second, false otherwise.
+ *
+ * @param compareOne the first string
+ * @param compareTwo the second string
+ * @return expression
+ */
+ public static Expression<Boolean> lt(@NonNull String compareOne, @NonNull String compareTwo) {
+ return new Expression<>("<", literal(compareOne), literal(compareTwo));
+ }
+
+ /**
+ * Returns true if the first input is greater than or equal to the second, false otherwise.
+ * The inputs must be numbers or strings, and both of the same type.
+ *
+ * @param compareOne the first expression
+ * @param compareTwo the second expression
+ * @return expression
+ */
+ public static Expression<Boolean> gte(@NonNull Expression compareOne, @NonNull Expression compareTwo) {
+ return new Expression<>(">=", compareOne, compareTwo);
+ }
+
+ /**
+ * Returns true if the first input is greater than or equal to the second, false otherwise.
+ *
+ * @param compareOne the first number
+ * @param compareTwo the second number
+ * @return expression
+ */
+ public static Expression<Boolean> gte(@NonNull Number compareOne, @NonNull Number compareTwo) {
+ return new Expression<>(">=", literal(compareOne), literal(compareTwo));
+ }
+
+ /**
+ * Returns true if the first input is greater than or equal to the second, false otherwise.
+ *
+ * @param compareOne the first string
+ * @param compareTwo the second string
+ * @return expression
+ */
+ public static Expression<Boolean> gte(@NonNull String compareOne, @NonNull String compareTwo) {
+ return new Expression<>(">=", literal(compareOne), literal(compareTwo));
+ }
+
+ /**
+ * Returns true if the first input is less than or equal to the second, false otherwise.
+ * The inputs must be numbers or strings, and both of the same type.
+ *
+ * @param compareOne the first expression
+ * @param compareTwo the second expression
+ * @return expression
+ */
+ public static Expression<Boolean> lte(@NonNull Expression compareOne, @NonNull Expression compareTwo) {
+ return new Expression<>("<=", compareOne, compareTwo);
+ }
+
+ /**
+ * Returns true if the first input is less than or equal to the second, false otherwise.
+ *
+ * @param compareOne the first number
+ * @param compareTwo the second number
+ * @return expression
+ */
+ public static Expression<Boolean> lte(@NonNull Number compareOne, @NonNull Number compareTwo) {
+ return new Expression<>("<=", literal(compareOne), literal(compareTwo));
+ }
+
+ /**
+ * Returns true if the first input is less than or equal to the second, false otherwise.
+ *
+ * @param compareOne the first string
+ * @param compareTwo the second string
+ * @return expression
+ */
+ public static Expression<Boolean> lte(@NonNull String compareOne, @NonNull String compareTwo) {
+ return new Expression<>("<=", literal(compareOne), literal(compareTwo));
+ }
+
+ /**
+ * Returns `true` if all the inputs are `true`, `false` otherwise.
+ * <p>
+ * The inputs are evaluated in order, and evaluation is short-circuiting:
+ * once an input expression evaluates to `false`,
+ * the result is `false` and no further input expressions are evaluated.
+ * </p>
+ *
+ * @param input expression input
+ * @return expression
+ */
+ public static Expression<Boolean> all(@NonNull Expression<Boolean>... input) {
+ return new Expression<>("all", input);
+ }
+
+ /**
+ * Returns `true` if any of the inputs are `true`, `false` otherwise.
+ * <p>
+ * The inputs are evaluated in order, and evaluation is short-circuiting:
+ * once an input expression evaluates to `true`,
+ * the result is `true` and no further input expressions are evaluated.
+ * </p>
+ *
+ * @param input expression input
+ * @return expression
+ */
+ public static Expression<Boolean> any(@NonNull Expression<Boolean>... input) {
+ return new Expression<>("any", input);
+ }
+
+ /**
+ * Logical negation. Returns `true` if the input is `false`, and `false` if the input is `true`.
+ *
+ * @param input expression input
+ * @return expression
+ */
+ public static Expression<Boolean> not(@NonNull Expression<Boolean> input) {
+ return new Expression<>("!", input);
+ }
+
+ /**
+ * Logical negation. Returns `true` if the input is `false`, and `false` if the input is `true`.
+ *
+ * @param input boolean input
+ * @return expression
+ */
+ public static Expression<Boolean> not(boolean input) {
+ return not(literal(input));
+ }
+
+ /**
+ * Selects the first output whose corresponding test condition evaluates to true.
+ *
+ * @param input expression input
+ * @return expression
+ */
+ public static Expression switchCase(@NonNull @Size(min = 1) Expression... input) {
+ return new Expression("case", input);
+ }
+
+ /**
+ * Selects the output whose label value matches the input value, or the fallback value if no match is found.
+ * The `input` can be any string or number expression.
+ * Each label can either be a single literal value or an array of values.
+ *
+ * @param input expression input
+ * @return expression
+ */
+ public static Expression match(@NonNull @Size(min = 2) Expression... input) {
+ return new Expression("match", input);
+ }
+
+ /**
+ * Selects the output whose label value matches the input value, or the fallback value if no match is found.
+ * The `input` can be any string or number expression.
+ * Each label can either be a single literal value or an array of values.
+ *
+ * @param input expression input
+ * @return expression
+ */
+ public static Expression match(@NonNull Expression input, @NonNull Stop... stops) {
+ Expression[] expressions = new Expression[stops.length * 2];
+ for (int i = 0; i < stops.length; i++) {
+ expressions[i * 2] = literal(stops[i].value);
+ expressions[i * 2 + 1] = literal(stops[i].output);
+ }
+ return match(join(new Expression[] {input}, expressions));
+ }
+
+ /**
+ * Evaluates each expression in turn until the first non-null value is obtained, and returns that value.
+ *
+ * @param input expression input
+ * @return expression
+ */
+ public static Expression coalesce(@NonNull Expression... input) {
+ return new Expression("coalesce", input);
+ }
+
+ //
+ // FeatureData
+ //
+
+ /**
+ * Gets the feature properties object.
+ * <p>
+ * Note that in some cases, it may be more efficient to use {@link #get(Expression)}} instead.
+ * </p>
+ *
+ * @return expression
+ */
+ public static Expression<Object> properties() {
+ return new Expression<>("properties");
+ }
+
+ /**
+ * Gets the feature's geometry type: Point, MultiPoint, LineString, MultiLineString, Polygon, MultiPolygon.
+ *
+ * @return expression
+ */
+ public static Expression<String> geometryType() {
+ return new Expression<>("geometry-type");
+ }
+
+ /**
+ * Gets the feature's id, if it has one.
+ *
+ * @return expression
+ */
+ public static Expression<Number> id() {
+ return new Expression<>("id");
+ }
+
+ //
+ // Heatmap
+ //
+
+ /**
+ * Gets the kernel density estimation of a pixel in a heatmap layer,
+ * which is a relative measure of how many data points are crowded around a particular pixel.
+ * Can only be used in the `heatmap-color` property.
+ *
+ * @return expression
+ */
+ public static Expression<Number> heatmapDensity() {
+ return new Expression<>("heatmap-density");
+ }
+
+ //
+ // Lookup
+ //
+
+ /**
+ * Retrieves an item from an array.
+ *
+ * @param number the index expression
+ * @param expression the array expression
+ * @return expression
+ */
+ public static Expression<Object> at(@NonNull Expression<Number> number, @NonNull Expression expression) {
+ return new Expression<>("at", number, expression);
+ }
+
+ /**
+ * Retrieves an item from an array.
+ *
+ * @param number the index expression
+ * @param expression the array expression
+ * @return expression
+ */
+ public static Expression<Object> at(@NonNull Number number, @NonNull Expression expression) {
+ return at(literal(number), expression);
+ }
+
+ /**
+ * Retrieves a property value from the current feature's properties,
+ * or from another object if a second argument is provided.
+ * Returns null if the requested property is missing.
+ *
+ * @param input expression input
+ * @return expression
+ */
+ public static Expression get(@NonNull Expression<String> input) {
+ return new Expression<>("get", input);
+ }
+
+ /**
+ * Retrieves a property value from the current feature's properties,
+ * or from another object if a second argument is provided.
+ * Returns null if the requested property is missing.
+ *
+ * @param input string input
+ * @return expression
+ */
+ public static Expression get(@NonNull String input) {
+ return get(literal(input));
+ }
+
+ /**
+ * Retrieves a property value from another object.
+ * Returns null if the requested property is missing.
+ *
+ * @param key a property value key
+ * @param object an expression object
+ * @return expression
+ */
+ public static Expression get(@NonNull Expression<String> key, @NonNull Expression<Object> object) {
+ return new Expression<>("get", key, object);
+ }
+
+ /**
+ * Retrieves a property value from another object.
+ * Returns null if the requested property is missing.
+ *
+ * @param key a property value key
+ * @param object an expression object
+ * @return expression
+ */
+ public static Expression get(@NonNull String key, @NonNull Expression<Object> object) {
+ return get(literal(key), object);
+ }
+
+ /**
+ * Tests for the presence of an property value in the current feature's properties.
+ *
+ * @param key the expression property value key
+ * @return expression
+ */
+ public static Expression<Boolean> has(@NonNull Expression<String> key) {
+ return new Expression<>("has", key);
+ }
+
+ /**
+ * Tests for the presence of an property value in the current feature's properties.
+ *
+ * @param key the property value key
+ * @return expression
+ */
+ public static Expression<Boolean> has(@NonNull String key) {
+ return has(literal(key));
+ }
+
+ /**
+ * Tests for the presence of an property value from another object.
+ *
+ * @param key the expression property value key
+ * @param object an expression object
+ * @return expression
+ */
+ public static Expression<Boolean> has(@NonNull Expression<String> key, @NonNull Expression<Object> object) {
+ return new Expression<>("has", key, object);
+ }
+
+ /**
+ * Tests for the presence of an property value from another object.
+ *
+ * @param key the property value key
+ * @param object an expression object
+ * @return expression
+ */
+ public static Expression<Boolean> has(@NonNull String key, @NonNull Expression<Object> object) {
+ return has(literal(key), object);
+ }
+
+ /**
+ * Gets the length of an array or string.
+ *
+ * @param expression an expression object or expression string
+ * @return expression
+ */
+ public static Expression<Number> length(@NonNull Expression<?> expression) {
+ return new Expression<>("length", expression);
+ }
+
+ /**
+ * Gets the length of an array or string.
+ *
+ * @param input a string
+ * @return expression
+ */
+ public static Expression<Number> length(@NonNull String input) {
+ return length(literal(input));
+ }
+
+ //
+ // Math
+ //
+
+ /**
+ * Returns mathematical constant ln(2).
+ *
+ * @return expression
+ */
+ public static Expression<Number> ln2() {
+ return new Expression<>("ln2");
+ }
+
+ /**
+ * Returns the mathematical constant pi.
+ *
+ * @return expression
+ */
+ public static Expression<Number> pi() {
+ return new Expression<>("pi");
+ }
+
+ /**
+ * Returns the mathematical constant e.
+ *
+ * @return expression
+ */
+ public static Expression<Number> e() {
+ return new Expression<>("e");
+ }
+
+ /**
+ * Returns the sum of the inputs.
+ *
+ * @param numbers the numbers to calculate the sum for
+ * @return expression
+ */
+ public static Expression<Number> sum(@Size(min = 2) Expression<Number>... numbers) {
+ return new Expression<>("+", numbers);
+ }
+
+ /**
+ * Returns the sum of the inputs.
+ *
+ * @param numbers the numbers to calculate the sum for
+ * @return expression
+ */
+ @SuppressWarnings("unchecked")
+ public static Expression<Number> sum(@Size(min = 2) Number... numbers) {
+ Expression<Number>[] numberExpression = (Expression<Number>[]) new Expression<?>[numbers.length];
+ for (int i = 0; i < numbers.length; i++) {
+ numberExpression[i] = literal(numbers[i]);
+ }
+ return sum(numberExpression);
+ }
+
+ /**
+ * Returns the product of the inputs.
+ *
+ * @param numbers the numbers to calculate the product for
+ * @return expression
+ */
+ public static Expression<Number> product(@Size(min = 2) Expression<Number>... numbers) {
+ return new Expression<>("*", numbers);
+ }
+
+ /**
+ * Returns the product of the inputs.
+ *
+ * @param numbers the numbers to calculate the product for
+ * @return expression
+ */
+ @SuppressWarnings("unchecked")
+ public static Expression<Number> product(@Size(min = 2) Number... numbers) {
+ Expression<Number>[] numberExpression = (Expression<Number>[]) new Expression<?>[numbers.length];
+ for (int i = 0; i < numbers.length; i++) {
+ numberExpression[i] = literal(numbers[i]);
+ }
+ return product(numberExpression);
+ }
+
+ /**
+ * Returns the result of subtracting a number from 0.
+ *
+ * @param number the number subtract from 0
+ * @return expression
+ */
+ public static Expression<Number> subtract(@NonNull Expression<Number> number) {
+ return new Expression<>("-", number);
+ }
+
+ /**
+ * Returns the result of subtracting a number from 0.
+ *
+ * @param number the number subtract from 0
+ * @return expression
+ */
+ public static Expression<Number> subtract(@NonNull Number number) {
+ return subtract(literal(number));
+ }
+
+ /**
+ * Returns the result of subtracting the second input from the first.
+ *
+ * @param first the first number
+ * @param second the second number
+ * @return expression
+ */
+ public static Expression<Number> subtract(@NonNull Expression<Number> first, @NonNull Expression<Number> second) {
+ return new Expression<>("-", first, second);
+ }
+
+ /**
+ * Returns the result of subtracting the second input from the first.
+ *
+ * @param first the first number
+ * @param second the second number
+ * @return expression
+ */
+ public static Expression<Number> subtract(@NonNull Number first, @NonNull Number second) {
+ return subtract(literal(first), literal(second));
+ }
+
+ /**
+ * Returns the result of floating point division of the first input by the second.
+ *
+ * @param first the first number
+ * @param second the second number
+ * @return expression
+ */
+ public static Expression<Number> division(@NonNull Expression<Number> first, @NonNull Expression<Number> second) {
+ return new Expression<>("/", first, second);
+ }
+
+ /**
+ * Returns the result of floating point division of the first input by the second.
+ *
+ * @param first the first number
+ * @param second the second number
+ * @return expression
+ */
+ public static Expression<Number> division(@NonNull Number first, @NonNull Number second) {
+ return division(literal(first), literal(second));
+ }
+
+ /**
+ * Returns the remainder after integer division of the first input by the second.
+ *
+ * @param first the first number
+ * @param second the second number
+ * @return expression
+ */
+ public static Expression<Number> mod(@NonNull Expression<Number> first, @NonNull Expression<Number> second) {
+ return new Expression<>("%", first, second);
+ }
+
+ /**
+ * Returns the remainder after integer division of the first input by the second.
+ *
+ * @param first the first number
+ * @param second the second number
+ * @return expression
+ */
+ public static Expression<Number> mod(@NonNull Number first, @NonNull Number second) {
+ return mod(literal(first), literal(second));
+ }
+
+ /**
+ * Returns the result of raising the first input to the power specified by the second.
+ *
+ * @param first the first number
+ * @param second the second number
+ * @return expression
+ */
+ public static Expression<Number> pow(@NonNull Expression<Number> first, @NonNull Expression<Number> second) {
+ return new Expression<>("^", first, second);
+ }
+
+ /**
+ * Returns the result of raising the first input to the power specified by the second.
+ *
+ * @param first the first number
+ * @param second the second number
+ * @return expression
+ */
+ public static Expression<Number> pow(@NonNull Number first, @NonNull Number second) {
+ return pow(literal(first), literal(second));
+ }
+
+ /**
+ * Returns the square root of the input
+ *
+ * @param number the number to take the square root from
+ * @return expression
+ */
+ public static Expression<Number> sqrt(@NonNull Expression<Number> number) {
+ return new Expression<>("sqrt", number);
+ }
+
+ /**
+ * Returns the square root of the input
+ *
+ * @param number the number to take the square root from
+ * @return expression
+ */
+ public static Expression<Number> sqrt(@NonNull Number number) {
+ return sqrt(literal(number));
+ }
+
+ /**
+ * Returns the base-ten logarithm of the input.
+ *
+ * @param number the number to take base-ten logarithm from
+ * @return expression
+ */
+ public static Expression<Number> log10(@NonNull Expression<Number> number) {
+ return new Expression<>("log10", number);
+ }
+
+ /**
+ * Returns the base-ten logarithm of the input.
+ *
+ * @param number the number to take base-ten logarithm from
+ * @return expression
+ */
+ public static Expression<Number> log10(@NonNull Number number) {
+ return log10(literal(number));
+ }
+
+ /**
+ * Returns the natural logarithm of the input.
+ *
+ * @param number the number to take natural logarithm from
+ * @return expression
+ */
+ public static Expression<Number> ln(Expression<Number> number) {
+ return new Expression<>("ln", number);
+ }
+
+ /**
+ * Returns the natural logarithm of the input.
+ *
+ * @param number the number to take natural logarithm from
+ * @return expression
+ */
+ public static Expression<Number> ln(Number number) {
+ return ln(literal(number));
+ }
+
+ /**
+ * Returns the base-two logarithm of the input.
+ *
+ * @param number the number to take base-two logarithm from
+ * @return expression
+ */
+ public static Expression<Number> log2(@NonNull Expression<Number> number) {
+ return new Expression<>("log2", number);
+ }
+
+ /**
+ * Returns the base-two logarithm of the input.
+ *
+ * @param number the number to take base-two logarithm from
+ * @return expression
+ */
+ public static Expression<Number> log2(@NonNull Number number) {
+ return log2(literal(number));
+ }
+
+ /**
+ * Returns the sine of the input.
+ *
+ * @param number the number to calculate the sine for
+ * @return expression
+ */
+ public static Expression<Number> sin(@NonNull Expression<Number> number) {
+ return new Expression<>("sin", number);
+ }
+
+ /**
+ * Returns the sine of the input.
+ *
+ * @param number the number to calculate the sine for
+ * @return expression
+ */
+ public static Expression<Number> sin(@NonNull Number number) {
+ return sin(literal(number));
+ }
+
+ /**
+ * Returns the cosine of the input.
+ *
+ * @param number the number to calculate the cosine for
+ * @return expression
+ */
+ public static Expression<Number> cos(@NonNull Expression<Number> number) {
+ return new Expression<>("cos", number);
+ }
+
+ /**
+ * Returns the cosine of the input.
+ *
+ * @param number the number to calculate the cosine for
+ * @return expression
+ */
+ public static Expression<Number> cos(@NonNull Number number) {
+ return new Expression<>("cos", literal(number));
+ }
+
+ /**
+ * Returns the tangent of the input.
+ *
+ * @param number the number to calculate the tangent for
+ * @return expression
+ */
+ public static Expression<Number> tan(@NonNull Expression<Number> number) {
+ return new Expression<>("tan", number);
+ }
+
+ /**
+ * Returns the tangent of the input.
+ *
+ * @param number the number to calculate the tangent for
+ * @return expression
+ */
+ public static Expression<Number> tan(@NonNull Number number) {
+ return new Expression<>("tan", literal(number));
+ }
+
+ /**
+ * Returns the arcsine of the input.
+ *
+ * @param number the number to calculate the arcsine for
+ * @return expression
+ */
+ public static Expression<Number> asin(@NonNull Expression<Number> number) {
+ return new Expression<>("asin", number);
+ }
+
+ /**
+ * Returns the arcsine of the input.
+ *
+ * @param number the number to calculate the arcsine for
+ * @return expression
+ */
+ public static Expression<Number> asin(@NonNull Number number) {
+ return asin(literal(number));
+ }
+
+ /**
+ * Returns the arccosine of the input.
+ *
+ * @param number the number to calculate the arccosine for
+ * @return expression
+ */
+ public static Expression<Number> acos(@NonNull Expression<Number> number) {
+ return new Expression<>("acos", number);
+ }
+
+ /**
+ * Returns the arccosine of the input.
+ *
+ * @param number the number to calculate the arccosine for
+ * @return expression
+ */
+ public static Expression<Number> acos(@NonNull Number number) {
+ return acos(literal(number));
+ }
+
+ /**
+ * Returns the arctangent of the input.
+ *
+ * @param number the number to calculate the arctangent for
+ * @return expression
+ */
+ public static Expression<Number> atan(@NonNull Expression<Number> number) {
+ return new Expression("atan", number);
+ }
+
+ /**
+ * Returns the arctangent of the input.
+ *
+ * @param number the number to calculate the arctangent for
+ * @return expression
+ */
+ public static Expression<Number> atan(@NonNull Number number) {
+ return atan(literal(number));
+ }
+
+ /**
+ * Returns the minimum value of the inputs.
+ *
+ * @param numbers varargs of numbers to get the minimum from
+ * @return expression
+ */
+ public static Expression<Number> min(@Size(min = 1) Expression<Number>... numbers) {
+ return new Expression<>("min", numbers);
+ }
+
+ /**
+ * Returns the minimum value of the inputs.
+ *
+ * @param numbers varargs of numbers to get the minimum from
+ * @return expression
+ */
+ @SuppressWarnings("unchecked")
+ public static Expression<Number> min(@Size(min = 1) Number... numbers) {
+ Expression<Number>[] numberExpression = (Expression<Number>[]) new Expression<?>[numbers.length];
+ for (int i = 0; i < numbers.length; i++) {
+ numberExpression[i] = literal(numbers[i]);
+ }
+ return min(numberExpression);
+ }
+
+ /**
+ * Returns the maximum value of the inputs.
+ *
+ * @param numbers varargs of numbers to get the maximum from
+ * @return expression
+ */
+ public static Expression<Number> max(@Size(min = 1) Expression<Number>... numbers) {
+ return new Expression<>("max", numbers);
+ }
+
+ /**
+ * Returns the maximum value of the inputs.
+ *
+ * @param numbers varargs of numbers to get the maximum from
+ * @return expression
+ */
+ @SuppressWarnings("unchecked")
+ public static Expression<Number> max(@Size(min = 1) Number... numbers) {
+ Expression<Number>[] numberExpression = (Expression<Number>[]) new Expression<?>[numbers.length];
+ for (int i = 0; i < numbers.length; i++) {
+ numberExpression[i] = literal(numbers[i]);
+ }
+ return max(numberExpression);
+ }
+
+ //
+ // String
+ //
+
+ /**
+ * Returns the input string converted to uppercase.
+ * <p>
+ * Follows the Unicode Default Case Conversion algorithm
+ * and the locale-insensitive case mappings in the Unicode Character Database.
+ * </p>
+ *
+ * @param string the string to upcase
+ * @return expression
+ */
+ public static Expression<String> upcase(@NonNull Expression<String> string) {
+ return new Expression<>("upcase", string);
+ }
+
+ /**
+ * Returns the input string converted to uppercase.
+ * <p>
+ * Follows the Unicode Default Case Conversion algorithm
+ * and the locale-insensitive case mappings in the Unicode Character Database.
+ * </p>
+ *
+ * @param string string to upcase
+ * @return expression
+ */
+ public static Expression<String> upcase(@NonNull String string) {
+ return upcase(literal(string));
+ }
+
+ /**
+ * Returns the input string converted to lowercase.
+ * <p>
+ * Follows the Unicode Default Case Conversion algorithm
+ * and the locale-insensitive case mappings in the Unicode Character Database.
+ * </p>
+ *
+ * @param input expression input
+ * @return expression
+ */
+ public static Expression<String> downcase(@NonNull Expression<String> input) {
+ return new Expression<>("downcase", input);
+ }
+
+ /**
+ * Returns the input string converted to lowercase.
+ * <p>
+ * Follows the Unicode Default Case Conversion algorithm
+ * and the locale-insensitive case mappings in the Unicode Character Database.
+ * </p>
+ *
+ * @param input string to downcase
+ * @return expression
+ */
+ public static Expression<String> downcase(@NonNull String input) {
+ return downcase(literal(input));
+ }
+
+ /**
+ * Returns a string consisting of the concatenation of the inputs.
+ *
+ * @param input expression input
+ * @return expression
+ */
+ public static Expression<String> concat(@NonNull Expression<String>... input) {
+ return new Expression<>("concat", input);
+ }
+
+ /**
+ * Returns a string consisting of the concatenation of the inputs.
+ *
+ * @param input expression input
+ * @return expression
+ */
+ @SuppressWarnings("unchecked")
+ public static Expression<String> concat(@NonNull String... input) {
+ Expression<String>[] stringExpression = (Expression<String>[]) new Expression<?>[input.length];
+ for (int i = 0; i < input.length; i++) {
+ stringExpression[i] = literal(input[i]);
+ }
+ return concat(stringExpression);
+ }
+
+ //
+ // Types
+ //
+
+ /**
+ * Asserts that the input is an array (optionally with a specific item type and length).
+ * If, when the input expression is evaluated, it is not of the asserted type,
+ * then this assertion will cause the whole expression to be aborted.
+ *
+ * @param input expression input
+ * @return expression
+ */
+ public static Expression<Boolean> array(@NonNull Expression input) {
+ return new Expression<>("array", input);
+ }
+
+ /**
+ * Returns a string describing the type of the given value.
+ *
+ * @param input expression input
+ * @return expression
+ */
+ public static Expression<String> typeOf(@NonNull Expression input) {
+ return new Expression<>("typeof", input);
+ }
+
+ /**
+ * Asserts that the input value is a string.
+ * If multiple values are provided, each one is evaluated in order until a string value is obtained.
+ * If none of the inputs are strings, the expression is an error.
+ *
+ * @param input expression input
+ * @return expression
+ */
+ public static Expression<Boolean> string(@NonNull Expression input) {
+ return new Expression<>("string", input);
+ }
+
+ /**
+ * Asserts that the input value is a number.
+ * If multiple values are provided, each one is evaluated in order until a number value is obtained.
+ * If none of the inputs are numbers, the expression is an error.
+ *
+ * @param input expression input
+ * @return expression
+ */
+ public static Expression<Boolean> number(@NonNull Expression input) {
+ return new Expression<>("number", input);
+ }
+
+ /**
+ * Asserts that the input value is a boolean.
+ * If multiple values are provided, each one is evaluated in order until a boolean value is obtained.
+ * If none of the inputs are booleans, the expression is an error.
+ *
+ * @param input expression input
+ * @return expression
+ */
+ public static Expression<Boolean> bool(@NonNull Expression input) {
+ return new Expression<>("boolean", input);
+ }
+
+ /**
+ * Asserts that the input value is an object. If it is not, the expression is an error
+ *
+ * @param input expression input
+ * @return expression
+ */
+ public static Expression<Boolean> object(@NonNull Expression input) {
+ return new Expression<>("object", input);
+ }
+
+ /**
+ * Converts the input value to a string.
+ * If the input is null, the result is null.
+ * If the input is a boolean, the result is true or false.
+ * If the input is a number, it is converted to a string by NumberToString in the ECMAScript Language Specification.
+ * If the input is a color, it is converted to a string of the form "rgba(r,g,b,a)",
+ * where `r`, `g`, and `b` are numerals ranging from 0 to 255, and `a` ranges from 0 to 1.
+ * Otherwise, the input is converted to a string in the format specified by the JSON.stringify in the ECMAScript
+ * Language Specification.
+ *
+ * @param input expression input
+ * @return expression
+ */
+ public static Expression<String> toString(@NonNull Expression input) {
+ return new Expression<>("to-string", input);
+ }
+
+ /**
+ * Converts the input value to a number, if possible.
+ * If the input is null or false, the result is 0.
+ * If the input is true, the result is 1.
+ * If the input is a string, it is converted to a number as specified by the ECMAScript Language Specification.
+ * If multiple values are provided, each one is evaluated in order until the first successful conversion is obtained.
+ * If none of the inputs can be converted, the expression is an error.
+ *
+ * @param input expression input
+ * @return expression
+ */
+ public static Expression<Number> toNumber(@NonNull Expression input) {
+ return new Expression<>("to-number", input);
+ }
+
+ /**
+ * "Converts the input value to a boolean. The result is `false` when then input is an empty string, 0, false,
+ * null, or NaN; otherwise it is true.
+ *
+ * @param input expression input
+ * @return expression
+ */
+ public static Expression<Boolean> toBool(@NonNull Expression input) {
+ return new Expression<>("to-boolean", input);
+ }
+
+ /**
+ * Converts the input value to a color. If multiple values are provided,
+ * each one is evaluated in order until the first successful conversion is obtained.
+ * If none of the inputs can be converted, the expression is an error.
+ *
+ * @param input expression input
+ * @return expression
+ */
+ public static Expression<Color> toColor(@NonNull Expression input) {
+ return new Expression<>("to-color", input);
+ }
+
+ //
+ // Variable binding
+ //
+
+ /**
+ * Binds input to named variables,
+ * which can then be referenced in the result expression using {@link #var(String)} or {@link #var(Expression)}.
+ *
+ * @param input expression input
+ * @return expression
+ */
+ public static Expression let(@Size(min = 1) Expression... input) {
+ return new Expression<>("let", input);
+ }
+
+ /**
+ * References variable bound using let.
+ *
+ * @param expression the variable naming expression that was bound with using let
+ * @return expression
+ */
+ public static Expression<Object> var(@NonNull Expression<String> expression) {
+ return new Expression<>("var", expression);
+ }
+
+ /**
+ * References variable bound using let.
+ *
+ * @param variableName the variable naming that was bound with using let
+ * @return expression
+ */
+ public static Expression var(@NonNull String variableName) {
+ return var(literal(variableName));
+ }
+
+ //
+ // Zoom
+ //
+
+ /**
+ * Gets the current zoom level.
+ * <p>
+ * Note that in style layout and paint properties,
+ * zoom may only appear as the input to a top-level step or interpolate expression.
+ * </p>
+ *
+ * @return expression
+ */
+ public static Expression<Number> zoom() {
+ return new Expression<>("zoom");
+ }
+
+ //
+ // Ramps, scales, curves
+ //
+
+ public static Stop stop(@NonNull Object stop, @NonNull Object value) {
+ return new Stop(stop, value);
+ }
+
+ /**
+ * Produces discrete, stepped results by evaluating a piecewise-constant function defined by pairs of
+ * input and output values (\"stops\"). The `input` may be any numeric expression (e.g., `[\"get\", \"population\"]`).
+ * Stop inputs must be numeric literals in strictly ascending order.
+ * Returns the output value of the stop just less than the input,
+ * or the first input if the input is less than the first stop.
+ *
+ * @param input the input value
+ * @param stops pair of input and output values
+ * @return expression
+ */
+ public static Expression step(@NonNull Number input, @NonNull Expression expression, Expression... stops) {
+ return step(literal(input), expression, stops);
+ }
+
+ /**
+ * Produces discrete, stepped results by evaluating a piecewise-constant function defined by pairs of
+ * input and output values (\"stops\"). The `input` may be any numeric expression (e.g., `[\"get\", \"population\"]`).
+ * Stop inputs must be numeric literals in strictly ascending order.
+ * Returns the output value of the stop just less than the input,
+ * or the first input if the input is less than the first stop.
+ *
+ * @param expression the input expression
+ * @param stops pair of input and output values
+ * @return expression
+ */
+ public static Expression step(@NonNull Expression<Number> input, @NonNull Expression expression, Expression... stops) {
+ return new Expression("step", join(new Expression[] {input, expression}, stops));
+ }
+
+ /**
+ * Produces discrete, stepped results by evaluating a piecewise-constant function defined by pairs of
+ * input and output values (\"stops\"). The `input` may be any numeric expression (e.g., `[\"get\", \"population\"]`).
+ * Stop inputs must be numeric literals in strictly ascending order.
+ * Returns the output value of the stop just less than the input,
+ * or the first input if the input is less than the first stop.
+ *
+ * @param input the input value
+ * @param stops pair of input and output values
+ * @return expression
+ */
+ public static Expression step(@NonNull Number input, @NonNull Expression expression, Stop... stops) {
+ Expression[] expressions = new Expression[stops.length * 2];
+ for (int i = 0; i < stops.length; i++) {
+ expressions[i * 2] = literal(stops[i].value);
+ expressions[i * 2 + 1] = literal(stops[i].output);
+ }
+ return step(literal(input), expression, expressions);
+ }
+
+ /**
+ * Produces discrete, stepped results by evaluating a piecewise-constant function defined by pairs of
+ * input and output values (\"stops\"). The `input` may be any numeric expression (e.g., `[\"get\", \"population\"]`).
+ * Stop inputs must be numeric literals in strictly ascending order.
+ * Returns the output value of the stop just less than the input,
+ * or the first input if the input is less than the first stop.
+ *
+ * @param input the input value
+ * @param stops pair of input and output values
+ * @return expression
+ */
+ public static Expression step(@NonNull Expression<Number> input, @NonNull Expression expression, Stop... stops) {
+ Expression[] expressions = new Expression[stops.length * 2];
+ for (int i = 0; i < stops.length; i++) {
+ expressions[i * 2] = literal(stops[i].value);
+ expressions[i * 2 + 1] = literal(stops[i].output);
+ }
+ return step(input, expression, expressions);
+ }
+
+ /**
+ * Produces continuous, smooth results by interpolating between pairs of input and output values (\"stops\").
+ * The `input` may be any numeric expression (e.g., `[\"get\", \"population\"]`).
+ * Stop inputs must be numeric literals in strictly ascending order.
+ * The output type must be `number`, `array&lt;number&gt;`, or `color`.
+ *
+ * @param interpolation type of interpolation
+ * @param number the input expression
+ * @param stops pair of input and output values
+ * @return expression
+ */
+ public static Expression interpolate(@NonNull Expression<Interpolator> interpolation,
+ @NonNull Expression<Number> number, Expression... stops) {
+ return new Expression("interpolate", join(new Expression[] {interpolation, number}, stops));
+ }
+
+ /**
+ * Produces continuous, smooth results by interpolating between pairs of input and output values (\"stops\").
+ * The `input` may be any numeric expression (e.g., `[\"get\", \"population\"]`).
+ * Stop inputs must be numeric literals in strictly ascending order.
+ * The output type must be `number`, `array&lt;number&gt;`, or `color`.
+ *
+ * @param interpolation type of interpolation
+ * @param number the input expression
+ * @param stops pair of input and output values
+ * @return expression
+ */
+ public static Expression interpolate(@NonNull Expression<Interpolator> interpolation,
+ @NonNull Expression<Number> number, Stop... stops) {
+ Expression[] expressions = new Expression[stops.length * 2];
+ for (int i = 0; i < stops.length; i++) {
+ expressions[i * 2] = literal(stops[i].value);
+ expressions[i * 2 + 1] = literal(stops[i].output);
+ }
+ return interpolate(interpolation, number, expressions);
+ }
+
+ /**
+ * interpolates linearly between the pair of stops just less than and just greater than the input.
+ *
+ * @return expression
+ */
+ public static Expression<Interpolator> linear() {
+ return new Expression<>("linear");
+ }
+
+ /**
+ * Interpolates exponentially between the stops just less than and just greater than the input.
+ * `base` controls the rate at which the output increases:
+ * higher values make the output increase more towards the high end of the range.
+ * With values close to 1 the output increases linearly.
+ *
+ * @param base value controlling the route at which the output increases
+ * @return expression
+ */
+ public static Expression<Interpolator> exponential(@NonNull Number base) {
+ return exponential(literal(base));
+ }
+
+ /**
+ * Interpolates exponentially between the stops just less than and just greater than the input.
+ * The parameter controls the rate at which the output increases:
+ * higher values make the output increase more towards the high end of the range.
+ * With values close to 1 the output increases linearly.
+ *
+ * @param expression base number expression
+ * @return expression
+ */
+ public static Expression<Interpolator> exponential(@NonNull Expression<Number> expression) {
+ return new Expression<>("exponential", expression);
+ }
+
+ /**
+ * Interpolates using the cubic bezier curve defined by the given control points.
+ *
+ * @param x1 x value of the first point of a cubic bezier, ranges from 0 to 1
+ * @param y1 y value of the first point of a cubic bezier, ranges from 0 to 1
+ * @param x2 x value of the second point of a cubic bezier, ranges from 0 to 1
+ * @param y2 y value fo the second point of a cubic bezier, ranges from 0 to 1
+ * @return expression
+ */
+ public static Expression<Interpolator> cubicBezier(@NonNull Expression<Number> x1, @NonNull Expression<Number> y1,
+ @NonNull Expression<Number> x2, @NonNull Expression<Number> y2) {
+ return new Expression<>("cubic-bezier", x1, y1, x2, y2);
+ }
+
+ /**
+ * Interpolates using the cubic bezier curve defined by the given control points.
+ *
+ * @param x1 x value of the first point of a cubic bezier, ranges from 0 to 1
+ * @param y1 y value of the first point of a cubic bezier, ranges from 0 to 1
+ * @param x2 x value of the second point of a cubic bezier, ranges from 0 to 1
+ * @param y2 y value fo the second point of a cubic bezier, ranges from 0 to 1
+ * @return expression
+ */
+ public static Expression<Interpolator> cubicBezier(@NonNull Number x1, @NonNull Number y1,
+ @NonNull Number x2, @NonNull Number y2) {
+ return cubicBezier(literal(x1), literal(y1), literal(x2), literal(y2));
+ }
+
+ /**
+ * Joins two expressions arrays.
+ * <p>
+ * This flattens the object array output of an expression from a nested expression hierarchy.
+ * </p>
+ *
+ * @param left the left part of an expression
+ * @param right the right part of an expression
+ * @return the joined expression
+ */
+ private static Expression[] join(Expression[] left, Expression[] right) {
+ Expression[] output = new Expression[left.length + right.length];
+ System.arraycopy(left, 0, output, 0, left.length);
+ System.arraycopy(right, 0, output, left.length, right.length);
+ return output;
+ }
+
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/Function.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/Function.java
index e1e40821b1..e7bb52ebb3 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/Function.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/functions/Function.java
@@ -279,7 +279,7 @@ public class Function<I, O> {
// noinspection unchecked
return (S) stops;
} catch (ClassCastException exception) {
- Timber.e(String.format("Stops: %s is a different type: %s", stops.getClass(), exception));
+ Timber.e(exception, "Stops: %s is a different type: ", stops.getClass());
return null;
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java
index 978fa29ef8..324b845dda 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java
@@ -8,8 +8,6 @@ import android.support.annotation.UiThread;
import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor;
-import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
-
/**
* The background color or pattern of the map.
*
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java
index 1a7df06031..ea96e4e9c3 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java
@@ -8,8 +8,6 @@ import android.support.annotation.UiThread;
import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor;
-import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
-
/**
* A filled circle.
*
@@ -278,6 +276,16 @@ public class CircleLayer extends Layer {
}
/**
+ * Get the CirclePitchAlignment property
+ *
+ * @return property wrapper value around String
+ */
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getCirclePitchAlignment() {
+ return (PropertyValue<String>) new PropertyValue("circle-pitch-alignment", nativeGetCirclePitchAlignment());
+ }
+
+ /**
* Get the CircleStrokeWidth property
*
* @return property wrapper value around Float
@@ -411,6 +419,8 @@ public class CircleLayer extends Layer {
private native Object nativeGetCirclePitchScale();
+ private native Object nativeGetCirclePitchAlignment();
+
private native Object nativeGetCircleStrokeWidth();
private native TransitionOptions nativeGetCircleStrokeWidthTransition();
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CustomLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CustomLayer.java
index 7807556b78..f77e7280f0 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CustomLayer.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CustomLayer.java
@@ -13,7 +13,16 @@ public class CustomLayer extends Layer {
long initializeFunction,
long renderFunction,
long deinitializeFunction) {
- initialize(id, initializeFunction, renderFunction, deinitializeFunction, context);
+ this(id, context, initializeFunction, renderFunction, 0L, deinitializeFunction);
+ }
+
+ public CustomLayer(String id,
+ long context,
+ long initializeFunction,
+ long renderFunction,
+ long contextLostFunction,
+ long deinitializeFunction) {
+ initialize(id, initializeFunction, renderFunction, contextLostFunction, deinitializeFunction, context);
}
public CustomLayer(long nativePtr) {
@@ -24,7 +33,8 @@ public class CustomLayer extends Layer {
nativeUpdate();
}
- protected native void initialize(String id, long initializeFunction, long renderFunction, long deinitializeFunction,
+ protected native void initialize(String id, long initializeFunction, long renderFunction,
+ long contextLostFunction, long deinitializeFunction,
long context);
protected native void nativeUpdate();
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java
index 6772da73b1..d4cdb2a425 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java
@@ -8,8 +8,6 @@ import android.support.annotation.UiThread;
import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor;
-import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
-
/**
* An extruded (3D) polygon.
*
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java
index 3719ae9e1b..e639823ee1 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java
@@ -8,8 +8,6 @@ import android.support.annotation.UiThread;
import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor;
-import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
-
/**
* A filled polygon with an optional stroked border.
*
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Layer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Layer.java
index 5015dd009d..5400e04589 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Layer.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Layer.java
@@ -2,6 +2,7 @@ package com.mapbox.mapboxsdk.style.layers;
import android.support.annotation.NonNull;
+import com.mapbox.mapboxsdk.style.expressions.Expression;
import com.mapbox.mapboxsdk.style.functions.Function;
/**
@@ -88,6 +89,14 @@ public abstract class Layer {
}
private Object convertValue(Object value) {
- return value != null && value instanceof Function ? ((Function) value).toValueObject() : value;
+ if (value != null) {
+ if (value instanceof Function) {
+ return ((Function) value).toValueObject();
+ } else if (value instanceof Expression) {
+ return ((Expression) value).toArray();
+ }
+ }
+ return value;
}
-}
+
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java
index ca106cc106..bbcfb98f07 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java
@@ -8,8 +8,6 @@ import android.support.annotation.UiThread;
import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor;
-import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
-
/**
* A stroked line.
*
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java
index 5e345268f9..8d6c7dd055 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java
@@ -160,6 +160,88 @@ public final class Property {
@Retention(RetentionPolicy.SOURCE)
public @interface ICON_TEXT_FIT {}
+ // ICON_ANCHOR: Part of the icon placed closest to the anchor.
+
+ /**
+ * The center of the icon is placed closest to the anchor.
+ */
+ public static final String ICON_ANCHOR_CENTER = "center";
+ /**
+ * The left side of the icon is placed closest to the anchor.
+ */
+ public static final String ICON_ANCHOR_LEFT = "left";
+ /**
+ * The right side of the icon is placed closest to the anchor.
+ */
+ public static final String ICON_ANCHOR_RIGHT = "right";
+ /**
+ * The top of the icon is placed closest to the anchor.
+ */
+ public static final String ICON_ANCHOR_TOP = "top";
+ /**
+ * The bottom of the icon is placed closest to the anchor.
+ */
+ public static final String ICON_ANCHOR_BOTTOM = "bottom";
+ /**
+ * The top left corner of the icon is placed closest to the anchor.
+ */
+ public static final String ICON_ANCHOR_TOP_LEFT = "top-left";
+ /**
+ * The top right corner of the icon is placed closest to the anchor.
+ */
+ public static final String ICON_ANCHOR_TOP_RIGHT = "top-right";
+ /**
+ * The bottom left corner of the icon is placed closest to the anchor.
+ */
+ public static final String ICON_ANCHOR_BOTTOM_LEFT = "bottom-left";
+ /**
+ * The bottom right corner of the icon is placed closest to the anchor.
+ */
+ public static final String ICON_ANCHOR_BOTTOM_RIGHT = "bottom-right";
+
+ /**
+ * Part of the icon placed closest to the anchor.
+ */
+ @StringDef({
+ ICON_ANCHOR_CENTER,
+ ICON_ANCHOR_LEFT,
+ ICON_ANCHOR_RIGHT,
+ ICON_ANCHOR_TOP,
+ ICON_ANCHOR_BOTTOM,
+ ICON_ANCHOR_TOP_LEFT,
+ ICON_ANCHOR_TOP_RIGHT,
+ ICON_ANCHOR_BOTTOM_LEFT,
+ ICON_ANCHOR_BOTTOM_RIGHT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ICON_ANCHOR {}
+
+ // ICON_PITCH_ALIGNMENT: Orientation of icon when map is pitched.
+
+ /**
+ * The icon is aligned to the plane of the map.
+ */
+ public static final String ICON_PITCH_ALIGNMENT_MAP = "map";
+ /**
+ * The icon is aligned to the plane of the viewport.
+ */
+ public static final String ICON_PITCH_ALIGNMENT_VIEWPORT = "viewport";
+ /**
+ * Automatically matches the value of {@link ICON_ROTATION_ALIGNMENT}.
+ */
+ public static final String ICON_PITCH_ALIGNMENT_AUTO = "auto";
+
+ /**
+ * Orientation of icon when map is pitched.
+ */
+ @StringDef({
+ ICON_PITCH_ALIGNMENT_MAP,
+ ICON_PITCH_ALIGNMENT_VIEWPORT,
+ ICON_PITCH_ALIGNMENT_AUTO,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ICON_PITCH_ALIGNMENT {}
+
// TEXT_PITCH_ALIGNMENT: Orientation of text when map is pitched.
/**
@@ -320,7 +402,7 @@ public final class Property {
@Retention(RetentionPolicy.SOURCE)
public @interface TEXT_TRANSFORM {}
- // FILL_TRANSLATE_ANCHOR: Controls the translation reference point.
+ // FILL_TRANSLATE_ANCHOR: Controls the frame of reference for `fill-translate`.
/**
* The fill is translated relative to the map.
@@ -332,7 +414,7 @@ public final class Property {
public static final String FILL_TRANSLATE_ANCHOR_VIEWPORT = "viewport";
/**
- * Controls the translation reference point.
+ * Controls the frame of reference for `fill-translate`.
*/
@StringDef({
FILL_TRANSLATE_ANCHOR_MAP,
@@ -341,7 +423,7 @@ public final class Property {
@Retention(RetentionPolicy.SOURCE)
public @interface FILL_TRANSLATE_ANCHOR {}
- // LINE_TRANSLATE_ANCHOR: Controls the translation reference point.
+ // LINE_TRANSLATE_ANCHOR: Controls the frame of reference for `line-translate`.
/**
* The line is translated relative to the map.
@@ -353,7 +435,7 @@ public final class Property {
public static final String LINE_TRANSLATE_ANCHOR_VIEWPORT = "viewport";
/**
- * Controls the translation reference point.
+ * Controls the frame of reference for `line-translate`.
*/
@StringDef({
LINE_TRANSLATE_ANCHOR_MAP,
@@ -362,7 +444,7 @@ public final class Property {
@Retention(RetentionPolicy.SOURCE)
public @interface LINE_TRANSLATE_ANCHOR {}
- // ICON_TRANSLATE_ANCHOR: Controls the translation reference point.
+ // ICON_TRANSLATE_ANCHOR: Controls the frame of reference for `icon-translate`.
/**
* Icons are translated relative to the map.
@@ -374,7 +456,7 @@ public final class Property {
public static final String ICON_TRANSLATE_ANCHOR_VIEWPORT = "viewport";
/**
- * Controls the translation reference point.
+ * Controls the frame of reference for `icon-translate`.
*/
@StringDef({
ICON_TRANSLATE_ANCHOR_MAP,
@@ -383,7 +465,7 @@ public final class Property {
@Retention(RetentionPolicy.SOURCE)
public @interface ICON_TRANSLATE_ANCHOR {}
- // TEXT_TRANSLATE_ANCHOR: Controls the translation reference point.
+ // TEXT_TRANSLATE_ANCHOR: Controls the frame of reference for `text-translate`.
/**
* The text is translated relative to the map.
@@ -395,7 +477,7 @@ public final class Property {
public static final String TEXT_TRANSLATE_ANCHOR_VIEWPORT = "viewport";
/**
- * Controls the translation reference point.
+ * Controls the frame of reference for `text-translate`.
*/
@StringDef({
TEXT_TRANSLATE_ANCHOR_MAP,
@@ -404,7 +486,7 @@ public final class Property {
@Retention(RetentionPolicy.SOURCE)
public @interface TEXT_TRANSLATE_ANCHOR {}
- // CIRCLE_TRANSLATE_ANCHOR: Controls the translation reference point.
+ // CIRCLE_TRANSLATE_ANCHOR: Controls the frame of reference for `circle-translate`.
/**
* The circle is translated relative to the map.
@@ -416,7 +498,7 @@ public final class Property {
public static final String CIRCLE_TRANSLATE_ANCHOR_VIEWPORT = "viewport";
/**
- * Controls the translation reference point.
+ * Controls the frame of reference for `circle-translate`.
*/
@StringDef({
CIRCLE_TRANSLATE_ANCHOR_MAP,
@@ -446,7 +528,28 @@ public final class Property {
@Retention(RetentionPolicy.SOURCE)
public @interface CIRCLE_PITCH_SCALE {}
- // FILL_EXTRUSION_TRANSLATE_ANCHOR: Controls the translation reference point.
+ // CIRCLE_PITCH_ALIGNMENT: Orientation of circle when map is pitched.
+
+ /**
+ * The circle is aligned to the plane of the map.
+ */
+ public static final String CIRCLE_PITCH_ALIGNMENT_MAP = "map";
+ /**
+ * The circle is aligned to the plane of the viewport.
+ */
+ public static final String CIRCLE_PITCH_ALIGNMENT_VIEWPORT = "viewport";
+
+ /**
+ * Orientation of circle when map is pitched.
+ */
+ @StringDef({
+ CIRCLE_PITCH_ALIGNMENT_MAP,
+ CIRCLE_PITCH_ALIGNMENT_VIEWPORT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface CIRCLE_PITCH_ALIGNMENT {}
+
+ // FILL_EXTRUSION_TRANSLATE_ANCHOR: Controls the frame of reference for `fill-extrusion-translate`.
/**
* The fill extrusion is translated relative to the map.
@@ -458,7 +561,7 @@ public final class Property {
public static final String FILL_EXTRUSION_TRANSLATE_ANCHOR_VIEWPORT = "viewport";
/**
- * Controls the translation reference point.
+ * Controls the frame of reference for `fill-extrusion-translate`.
*/
@StringDef({
FILL_EXTRUSION_TRANSLATE_ANCHOR_MAP,
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java
index 73896b7901..fe164343b5 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java
@@ -5,8 +5,11 @@ package com.mapbox.mapboxsdk.style.layers;
import android.annotation.SuppressLint;
import android.support.annotation.ColorInt;
-import com.mapbox.mapboxsdk.style.functions.Function;
import com.mapbox.mapboxsdk.style.functions.CameraFunction;
+import com.mapbox.mapboxsdk.style.expressions.Expression;
+import com.mapbox.mapboxsdk.style.functions.Function;
+
+import java.util.Locale;
/**
* Constructs paint/layout properties for Layers
@@ -32,6 +35,7 @@ public class PropertyFactory {
* @param function the visibility function
* @return property wrapper around a String function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, String>> visibility(Function<T, String> function) {
return new LayoutPropertyValue<>("visibility", function);
}
@@ -46,6 +50,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("fill-antialias", value);
}
+ /**
+ * Whether or not the fill should be antialiased.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> fillAntialias(Expression expression) {
+ return new PaintPropertyValue<>("fill-antialias", expression);
+ }
+
/**
* Whether or not the fill should be antialiased.
@@ -54,6 +68,7 @@ public class PropertyFactory {
* @param function a wrapper {@link CameraFunction} for Boolean
* @return property wrapper around a Boolean function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, Boolean>> fillAntialias(CameraFunction<Z, Boolean> function) {
return new PaintPropertyValue<>("fill-antialias", function);
}
@@ -68,6 +83,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("fill-opacity", value);
}
+ /**
+ * The opacity of the entire fill layer. In contrast to the {@link PropertyFactory#fillColor}, this value will also affect the 1px stroke around the fill, if the stroke is used.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> fillOpacity(Expression expression) {
+ return new PaintPropertyValue<>("fill-opacity", expression);
+ }
+
/**
* The opacity of the entire fill layer. In contrast to the {@link PropertyFactory#fillColor}, this value will also affect the 1px stroke around the fill, if the stroke is used.
@@ -76,6 +101,7 @@ public class PropertyFactory {
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, Float>> fillOpacity(Function<T, Float> function) {
return new PaintPropertyValue<>("fill-opacity", function);
}
@@ -100,6 +126,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("fill-color", value);
}
+ /**
+ * The color of the filled part of this layer. This color can be specified as `rgba` with an alpha component and the color's opacity will not affect the opacity of the 1px stroke, if it is used.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> fillColor(Expression expression) {
+ return new PaintPropertyValue<>("fill-color", expression);
+ }
+
/**
* The color of the filled part of this layer. This color can be specified as `rgba` with an alpha component and the color's opacity will not affect the opacity of the 1px stroke, if it is used.
@@ -108,6 +144,7 @@ public class PropertyFactory {
* @param function a wrapper function for String
* @return property wrapper around a String function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, String>> fillColor(Function<T, String> function) {
return new PaintPropertyValue<>("fill-color", function);
}
@@ -132,6 +169,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("fill-outline-color", value);
}
+ /**
+ * The outline color of the fill. Matches the value of {@link PropertyFactory#fillColor} if unspecified.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> fillOutlineColor(Expression expression) {
+ return new PaintPropertyValue<>("fill-outline-color", expression);
+ }
+
/**
* The outline color of the fill. Matches the value of {@link PropertyFactory#fillColor} if unspecified.
@@ -140,6 +187,7 @@ public class PropertyFactory {
* @param function a wrapper function for String
* @return property wrapper around a String function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, String>> fillOutlineColor(Function<T, String> function) {
return new PaintPropertyValue<>("fill-outline-color", function);
}
@@ -154,6 +202,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("fill-translate", value);
}
+ /**
+ * The geometry's offset. Values are [x, y] where negatives indicate left and up, respectively.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> fillTranslate(Expression expression) {
+ return new PaintPropertyValue<>("fill-translate", expression);
+ }
+
/**
* The geometry's offset. Values are [x, y] where negatives indicate left and up, respectively.
@@ -162,12 +220,13 @@ public class PropertyFactory {
* @param function a wrapper {@link CameraFunction} for Float[]
* @return property wrapper around a Float[] function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, Float[]>> fillTranslate(CameraFunction<Z, Float[]> function) {
return new PaintPropertyValue<>("fill-translate", function);
}
/**
- * Controls the translation reference point.
+ * Controls the frame of reference for {@link PropertyFactory#fillTranslate}.
*
* @param value a String value
* @return property wrapper around String
@@ -176,14 +235,25 @@ public class PropertyFactory {
return new PaintPropertyValue<>("fill-translate-anchor", value);
}
+ /**
+ * Controls the frame of reference for {@link PropertyFactory#fillTranslate}.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> fillTranslateAnchor(Expression expression) {
+ return new PaintPropertyValue<>("fill-translate-anchor", expression);
+ }
+
/**
- * Controls the translation reference point.
+ * Controls the frame of reference for {@link PropertyFactory#fillTranslate}.
*
* @param <Z> the zoom parameter type
* @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> fillTranslateAnchor(CameraFunction<Z, String> function) {
return new PaintPropertyValue<>("fill-translate-anchor", function);
}
@@ -198,6 +268,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("fill-pattern", value);
}
+ /**
+ * Name of image in sprite to use for drawing image fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512).
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> fillPattern(Expression expression) {
+ return new PaintPropertyValue<>("fill-pattern", expression);
+ }
+
/**
* Name of image in sprite to use for drawing image fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512).
@@ -206,6 +286,7 @@ public class PropertyFactory {
* @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> fillPattern(CameraFunction<Z, String> function) {
return new PaintPropertyValue<>("fill-pattern", function);
}
@@ -220,6 +301,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("line-opacity", value);
}
+ /**
+ * The opacity at which the line will be drawn.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> lineOpacity(Expression expression) {
+ return new PaintPropertyValue<>("line-opacity", expression);
+ }
+
/**
* The opacity at which the line will be drawn.
@@ -228,6 +319,7 @@ public class PropertyFactory {
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, Float>> lineOpacity(Function<T, Float> function) {
return new PaintPropertyValue<>("line-opacity", function);
}
@@ -252,6 +344,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("line-color", value);
}
+ /**
+ * The color with which the line will be drawn.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> lineColor(Expression expression) {
+ return new PaintPropertyValue<>("line-color", expression);
+ }
+
/**
* The color with which the line will be drawn.
@@ -260,6 +362,7 @@ public class PropertyFactory {
* @param function a wrapper function for String
* @return property wrapper around a String function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, String>> lineColor(Function<T, String> function) {
return new PaintPropertyValue<>("line-color", function);
}
@@ -274,6 +377,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("line-translate", value);
}
+ /**
+ * The geometry's offset. Values are [x, y] where negatives indicate left and up, respectively.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> lineTranslate(Expression expression) {
+ return new PaintPropertyValue<>("line-translate", expression);
+ }
+
/**
* The geometry's offset. Values are [x, y] where negatives indicate left and up, respectively.
@@ -282,12 +395,13 @@ public class PropertyFactory {
* @param function a wrapper {@link CameraFunction} for Float[]
* @return property wrapper around a Float[] function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, Float[]>> lineTranslate(CameraFunction<Z, Float[]> function) {
return new PaintPropertyValue<>("line-translate", function);
}
/**
- * Controls the translation reference point.
+ * Controls the frame of reference for {@link PropertyFactory#lineTranslate}.
*
* @param value a String value
* @return property wrapper around String
@@ -296,14 +410,25 @@ public class PropertyFactory {
return new PaintPropertyValue<>("line-translate-anchor", value);
}
+ /**
+ * Controls the frame of reference for {@link PropertyFactory#lineTranslate}.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> lineTranslateAnchor(Expression expression) {
+ return new PaintPropertyValue<>("line-translate-anchor", expression);
+ }
+
/**
- * Controls the translation reference point.
+ * Controls the frame of reference for {@link PropertyFactory#lineTranslate}.
*
* @param <Z> the zoom parameter type
* @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> lineTranslateAnchor(CameraFunction<Z, String> function) {
return new PaintPropertyValue<>("line-translate-anchor", function);
}
@@ -318,6 +443,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("line-width", value);
}
+ /**
+ * Stroke thickness.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> lineWidth(Expression expression) {
+ return new PaintPropertyValue<>("line-width", expression);
+ }
+
/**
* Stroke thickness.
@@ -326,6 +461,7 @@ public class PropertyFactory {
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, Float>> lineWidth(Function<T, Float> function) {
return new PaintPropertyValue<>("line-width", function);
}
@@ -340,6 +476,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("line-gap-width", value);
}
+ /**
+ * Draws a line casing outside of a line's actual path. Value indicates the width of the inner gap.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> lineGapWidth(Expression expression) {
+ return new PaintPropertyValue<>("line-gap-width", expression);
+ }
+
/**
* Draws a line casing outside of a line's actual path. Value indicates the width of the inner gap.
@@ -348,6 +494,7 @@ public class PropertyFactory {
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, Float>> lineGapWidth(Function<T, Float> function) {
return new PaintPropertyValue<>("line-gap-width", function);
}
@@ -362,6 +509,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("line-offset", value);
}
+ /**
+ * The line's offset. For linear features, a positive value offsets the line to the right, relative to the direction of the line, and a negative value to the left. For polygon features, a positive value results in an inset, and a negative value results in an outset.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> lineOffset(Expression expression) {
+ return new PaintPropertyValue<>("line-offset", expression);
+ }
+
/**
* The line's offset. For linear features, a positive value offsets the line to the right, relative to the direction of the line, and a negative value to the left. For polygon features, a positive value results in an inset, and a negative value results in an outset.
@@ -370,6 +527,7 @@ public class PropertyFactory {
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, Float>> lineOffset(Function<T, Float> function) {
return new PaintPropertyValue<>("line-offset", function);
}
@@ -384,6 +542,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("line-blur", value);
}
+ /**
+ * Blur applied to the line, in density-independent pixels.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> lineBlur(Expression expression) {
+ return new PaintPropertyValue<>("line-blur", expression);
+ }
+
/**
* Blur applied to the line, in density-independent pixels.
@@ -392,6 +560,7 @@ public class PropertyFactory {
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, Float>> lineBlur(Function<T, Float> function) {
return new PaintPropertyValue<>("line-blur", function);
}
@@ -406,6 +575,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("line-dasharray", value);
}
+ /**
+ * Specifies the lengths of the alternating dashes and gaps that form the dash pattern. The lengths are later scaled by the line width. To convert a dash length to density-independent pixels, multiply the length by the current line width.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> lineDasharray(Expression expression) {
+ return new PaintPropertyValue<>("line-dasharray", expression);
+ }
+
/**
* Specifies the lengths of the alternating dashes and gaps that form the dash pattern. The lengths are later scaled by the line width. To convert a dash length to density-independent pixels, multiply the length by the current line width.
@@ -414,6 +593,7 @@ public class PropertyFactory {
* @param function a wrapper {@link CameraFunction} for Float[]
* @return property wrapper around a Float[] function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, Float[]>> lineDasharray(CameraFunction<Z, Float[]> function) {
return new PaintPropertyValue<>("line-dasharray", function);
}
@@ -428,6 +608,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("line-pattern", value);
}
+ /**
+ * Name of image in sprite to use for drawing image lines. For seamless patterns, image width must be a factor of two (2, 4, 8, ..., 512).
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> linePattern(Expression expression) {
+ return new PaintPropertyValue<>("line-pattern", expression);
+ }
+
/**
* Name of image in sprite to use for drawing image lines. For seamless patterns, image width must be a factor of two (2, 4, 8, ..., 512).
@@ -436,6 +626,7 @@ public class PropertyFactory {
* @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> linePattern(CameraFunction<Z, String> function) {
return new PaintPropertyValue<>("line-pattern", function);
}
@@ -450,6 +641,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("icon-opacity", value);
}
+ /**
+ * The opacity at which the icon will be drawn.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> iconOpacity(Expression expression) {
+ return new PaintPropertyValue<>("icon-opacity", expression);
+ }
+
/**
* The opacity at which the icon will be drawn.
@@ -458,6 +659,7 @@ public class PropertyFactory {
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, Float>> iconOpacity(Function<T, Float> function) {
return new PaintPropertyValue<>("icon-opacity", function);
}
@@ -482,6 +684,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("icon-color", value);
}
+ /**
+ * The color of the icon. This can only be used with sdf icons.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> iconColor(Expression expression) {
+ return new PaintPropertyValue<>("icon-color", expression);
+ }
+
/**
* The color of the icon. This can only be used with sdf icons.
@@ -490,6 +702,7 @@ public class PropertyFactory {
* @param function a wrapper function for String
* @return property wrapper around a String function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, String>> iconColor(Function<T, String> function) {
return new PaintPropertyValue<>("icon-color", function);
}
@@ -514,6 +727,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("icon-halo-color", value);
}
+ /**
+ * The color of the icon's halo. Icon halos can only be used with SDF icons.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> iconHaloColor(Expression expression) {
+ return new PaintPropertyValue<>("icon-halo-color", expression);
+ }
+
/**
* The color of the icon's halo. Icon halos can only be used with SDF icons.
@@ -522,6 +745,7 @@ public class PropertyFactory {
* @param function a wrapper function for String
* @return property wrapper around a String function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, String>> iconHaloColor(Function<T, String> function) {
return new PaintPropertyValue<>("icon-halo-color", function);
}
@@ -536,6 +760,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("icon-halo-width", value);
}
+ /**
+ * Distance of halo to the icon outline.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> iconHaloWidth(Expression expression) {
+ return new PaintPropertyValue<>("icon-halo-width", expression);
+ }
+
/**
* Distance of halo to the icon outline.
@@ -544,6 +778,7 @@ public class PropertyFactory {
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, Float>> iconHaloWidth(Function<T, Float> function) {
return new PaintPropertyValue<>("icon-halo-width", function);
}
@@ -558,6 +793,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("icon-halo-blur", value);
}
+ /**
+ * Fade out the halo towards the outside.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> iconHaloBlur(Expression expression) {
+ return new PaintPropertyValue<>("icon-halo-blur", expression);
+ }
+
/**
* Fade out the halo towards the outside.
@@ -566,6 +811,7 @@ public class PropertyFactory {
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, Float>> iconHaloBlur(Function<T, Float> function) {
return new PaintPropertyValue<>("icon-halo-blur", function);
}
@@ -580,6 +826,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("icon-translate", value);
}
+ /**
+ * Distance that the icon's anchor is moved from its original placement. Positive values indicate right and down, while negative values indicate left and up.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> iconTranslate(Expression expression) {
+ return new PaintPropertyValue<>("icon-translate", expression);
+ }
+
/**
* Distance that the icon's anchor is moved from its original placement. Positive values indicate right and down, while negative values indicate left and up.
@@ -588,12 +844,13 @@ public class PropertyFactory {
* @param function a wrapper {@link CameraFunction} for Float[]
* @return property wrapper around a Float[] function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, Float[]>> iconTranslate(CameraFunction<Z, Float[]> function) {
return new PaintPropertyValue<>("icon-translate", function);
}
/**
- * Controls the translation reference point.
+ * Controls the frame of reference for {@link PropertyFactory#iconTranslate}.
*
* @param value a String value
* @return property wrapper around String
@@ -602,14 +859,25 @@ public class PropertyFactory {
return new PaintPropertyValue<>("icon-translate-anchor", value);
}
+ /**
+ * Controls the frame of reference for {@link PropertyFactory#iconTranslate}.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> iconTranslateAnchor(Expression expression) {
+ return new PaintPropertyValue<>("icon-translate-anchor", expression);
+ }
+
/**
- * Controls the translation reference point.
+ * Controls the frame of reference for {@link PropertyFactory#iconTranslate}.
*
* @param <Z> the zoom parameter type
* @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> iconTranslateAnchor(CameraFunction<Z, String> function) {
return new PaintPropertyValue<>("icon-translate-anchor", function);
}
@@ -624,6 +892,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("text-opacity", value);
}
+ /**
+ * The opacity at which the text will be drawn.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> textOpacity(Expression expression) {
+ return new PaintPropertyValue<>("text-opacity", expression);
+ }
+
/**
* The opacity at which the text will be drawn.
@@ -632,6 +910,7 @@ public class PropertyFactory {
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, Float>> textOpacity(Function<T, Float> function) {
return new PaintPropertyValue<>("text-opacity", function);
}
@@ -656,6 +935,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("text-color", value);
}
+ /**
+ * The color with which the text will be drawn.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> textColor(Expression expression) {
+ return new PaintPropertyValue<>("text-color", expression);
+ }
+
/**
* The color with which the text will be drawn.
@@ -664,6 +953,7 @@ public class PropertyFactory {
* @param function a wrapper function for String
* @return property wrapper around a String function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, String>> textColor(Function<T, String> function) {
return new PaintPropertyValue<>("text-color", function);
}
@@ -688,6 +978,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("text-halo-color", value);
}
+ /**
+ * The color of the text's halo, which helps it stand out from backgrounds.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> textHaloColor(Expression expression) {
+ return new PaintPropertyValue<>("text-halo-color", expression);
+ }
+
/**
* The color of the text's halo, which helps it stand out from backgrounds.
@@ -696,6 +996,7 @@ public class PropertyFactory {
* @param function a wrapper function for String
* @return property wrapper around a String function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, String>> textHaloColor(Function<T, String> function) {
return new PaintPropertyValue<>("text-halo-color", function);
}
@@ -710,6 +1011,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("text-halo-width", value);
}
+ /**
+ * Distance of halo to the font outline. Max text halo width is 1/4 of the font-size.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> textHaloWidth(Expression expression) {
+ return new PaintPropertyValue<>("text-halo-width", expression);
+ }
+
/**
* Distance of halo to the font outline. Max text halo width is 1/4 of the font-size.
@@ -718,6 +1029,7 @@ public class PropertyFactory {
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, Float>> textHaloWidth(Function<T, Float> function) {
return new PaintPropertyValue<>("text-halo-width", function);
}
@@ -732,6 +1044,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("text-halo-blur", value);
}
+ /**
+ * The halo's fadeout distance towards the outside.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> textHaloBlur(Expression expression) {
+ return new PaintPropertyValue<>("text-halo-blur", expression);
+ }
+
/**
* The halo's fadeout distance towards the outside.
@@ -740,6 +1062,7 @@ public class PropertyFactory {
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, Float>> textHaloBlur(Function<T, Float> function) {
return new PaintPropertyValue<>("text-halo-blur", function);
}
@@ -754,6 +1077,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("text-translate", value);
}
+ /**
+ * Distance that the text's anchor is moved from its original placement. Positive values indicate right and down, while negative values indicate left and up.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> textTranslate(Expression expression) {
+ return new PaintPropertyValue<>("text-translate", expression);
+ }
+
/**
* Distance that the text's anchor is moved from its original placement. Positive values indicate right and down, while negative values indicate left and up.
@@ -762,12 +1095,13 @@ public class PropertyFactory {
* @param function a wrapper {@link CameraFunction} for Float[]
* @return property wrapper around a Float[] function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, Float[]>> textTranslate(CameraFunction<Z, Float[]> function) {
return new PaintPropertyValue<>("text-translate", function);
}
/**
- * Controls the translation reference point.
+ * Controls the frame of reference for {@link PropertyFactory#textTranslate}.
*
* @param value a String value
* @return property wrapper around String
@@ -776,14 +1110,25 @@ public class PropertyFactory {
return new PaintPropertyValue<>("text-translate-anchor", value);
}
+ /**
+ * Controls the frame of reference for {@link PropertyFactory#textTranslate}.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> textTranslateAnchor(Expression expression) {
+ return new PaintPropertyValue<>("text-translate-anchor", expression);
+ }
+
/**
- * Controls the translation reference point.
+ * Controls the frame of reference for {@link PropertyFactory#textTranslate}.
*
* @param <Z> the zoom parameter type
* @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> textTranslateAnchor(CameraFunction<Z, String> function) {
return new PaintPropertyValue<>("text-translate-anchor", function);
}
@@ -798,6 +1143,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("circle-radius", value);
}
+ /**
+ * Circle radius.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> circleRadius(Expression expression) {
+ return new PaintPropertyValue<>("circle-radius", expression);
+ }
+
/**
* Circle radius.
@@ -806,6 +1161,7 @@ public class PropertyFactory {
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, Float>> circleRadius(Function<T, Float> function) {
return new PaintPropertyValue<>("circle-radius", function);
}
@@ -830,6 +1186,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("circle-color", value);
}
+ /**
+ * The fill color of the circle.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> circleColor(Expression expression) {
+ return new PaintPropertyValue<>("circle-color", expression);
+ }
+
/**
* The fill color of the circle.
@@ -838,6 +1204,7 @@ public class PropertyFactory {
* @param function a wrapper function for String
* @return property wrapper around a String function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, String>> circleColor(Function<T, String> function) {
return new PaintPropertyValue<>("circle-color", function);
}
@@ -852,6 +1219,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("circle-blur", value);
}
+ /**
+ * Amount to blur the circle. 1 blurs the circle such that only the centerpoint is full opacity.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> circleBlur(Expression expression) {
+ return new PaintPropertyValue<>("circle-blur", expression);
+ }
+
/**
* Amount to blur the circle. 1 blurs the circle such that only the centerpoint is full opacity.
@@ -860,6 +1237,7 @@ public class PropertyFactory {
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, Float>> circleBlur(Function<T, Float> function) {
return new PaintPropertyValue<>("circle-blur", function);
}
@@ -874,6 +1252,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("circle-opacity", value);
}
+ /**
+ * The opacity at which the circle will be drawn.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> circleOpacity(Expression expression) {
+ return new PaintPropertyValue<>("circle-opacity", expression);
+ }
+
/**
* The opacity at which the circle will be drawn.
@@ -882,6 +1270,7 @@ public class PropertyFactory {
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, Float>> circleOpacity(Function<T, Float> function) {
return new PaintPropertyValue<>("circle-opacity", function);
}
@@ -896,6 +1285,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("circle-translate", value);
}
+ /**
+ * The geometry's offset. Values are [x, y] where negatives indicate left and up, respectively.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> circleTranslate(Expression expression) {
+ return new PaintPropertyValue<>("circle-translate", expression);
+ }
+
/**
* The geometry's offset. Values are [x, y] where negatives indicate left and up, respectively.
@@ -904,12 +1303,13 @@ public class PropertyFactory {
* @param function a wrapper {@link CameraFunction} for Float[]
* @return property wrapper around a Float[] function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, Float[]>> circleTranslate(CameraFunction<Z, Float[]> function) {
return new PaintPropertyValue<>("circle-translate", function);
}
/**
- * Controls the translation reference point.
+ * Controls the frame of reference for {@link PropertyFactory#circleTranslate}.
*
* @param value a String value
* @return property wrapper around String
@@ -918,14 +1318,25 @@ public class PropertyFactory {
return new PaintPropertyValue<>("circle-translate-anchor", value);
}
+ /**
+ * Controls the frame of reference for {@link PropertyFactory#circleTranslate}.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> circleTranslateAnchor(Expression expression) {
+ return new PaintPropertyValue<>("circle-translate-anchor", expression);
+ }
+
/**
- * Controls the translation reference point.
+ * Controls the frame of reference for {@link PropertyFactory#circleTranslate}.
*
* @param <Z> the zoom parameter type
* @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> circleTranslateAnchor(CameraFunction<Z, String> function) {
return new PaintPropertyValue<>("circle-translate-anchor", function);
}
@@ -940,6 +1351,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("circle-pitch-scale", value);
}
+ /**
+ * Controls the scaling behavior of the circle when the map is pitched.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> circlePitchScale(Expression expression) {
+ return new PaintPropertyValue<>("circle-pitch-scale", expression);
+ }
+
/**
* Controls the scaling behavior of the circle when the map is pitched.
@@ -948,11 +1369,45 @@ public class PropertyFactory {
* @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> circlePitchScale(CameraFunction<Z, String> function) {
return new PaintPropertyValue<>("circle-pitch-scale", function);
}
/**
+ * Orientation of circle when map is pitched.
+ *
+ * @param value a String value
+ * @return property wrapper around String
+ */
+ public static PropertyValue<String> circlePitchAlignment(@Property.CIRCLE_PITCH_ALIGNMENT String value) {
+ return new PaintPropertyValue<>("circle-pitch-alignment", value);
+ }
+
+ /**
+ * Orientation of circle when map is pitched.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> circlePitchAlignment(Expression expression) {
+ return new PaintPropertyValue<>("circle-pitch-alignment", expression);
+ }
+
+
+ /**
+ * Orientation of circle when map is pitched.
+ *
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for String
+ * @return property wrapper around a String function
+ */
+ @Deprecated
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> circlePitchAlignment(CameraFunction<Z, String> function) {
+ return new PaintPropertyValue<>("circle-pitch-alignment", function);
+ }
+
+ /**
* The width of the circle's stroke. Strokes are placed outside of the {@link PropertyFactory#circleRadius}.
*
* @param value a Float value
@@ -962,6 +1417,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("circle-stroke-width", value);
}
+ /**
+ * The width of the circle's stroke. Strokes are placed outside of the {@link PropertyFactory#circleRadius}.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> circleStrokeWidth(Expression expression) {
+ return new PaintPropertyValue<>("circle-stroke-width", expression);
+ }
+
/**
* The width of the circle's stroke. Strokes are placed outside of the {@link PropertyFactory#circleRadius}.
@@ -970,6 +1435,7 @@ public class PropertyFactory {
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, Float>> circleStrokeWidth(Function<T, Float> function) {
return new PaintPropertyValue<>("circle-stroke-width", function);
}
@@ -994,6 +1460,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("circle-stroke-color", value);
}
+ /**
+ * The stroke color of the circle.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> circleStrokeColor(Expression expression) {
+ return new PaintPropertyValue<>("circle-stroke-color", expression);
+ }
+
/**
* The stroke color of the circle.
@@ -1002,6 +1478,7 @@ public class PropertyFactory {
* @param function a wrapper function for String
* @return property wrapper around a String function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, String>> circleStrokeColor(Function<T, String> function) {
return new PaintPropertyValue<>("circle-stroke-color", function);
}
@@ -1016,6 +1493,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("circle-stroke-opacity", value);
}
+ /**
+ * The opacity of the circle's stroke.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> circleStrokeOpacity(Expression expression) {
+ return new PaintPropertyValue<>("circle-stroke-opacity", expression);
+ }
+
/**
* The opacity of the circle's stroke.
@@ -1024,6 +1511,7 @@ public class PropertyFactory {
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, Float>> circleStrokeOpacity(Function<T, Float> function) {
return new PaintPropertyValue<>("circle-stroke-opacity", function);
}
@@ -1038,6 +1526,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("fill-extrusion-opacity", value);
}
+ /**
+ * The opacity of the entire fill extrusion layer. This is rendered on a per-layer, not per-feature, basis, and data-driven styling is not available.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> fillExtrusionOpacity(Expression expression) {
+ return new PaintPropertyValue<>("fill-extrusion-opacity", expression);
+ }
+
/**
* The opacity of the entire fill extrusion layer. This is rendered on a per-layer, not per-feature, basis, and data-driven styling is not available.
@@ -1046,6 +1544,7 @@ public class PropertyFactory {
* @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> fillExtrusionOpacity(CameraFunction<Z, Float> function) {
return new PaintPropertyValue<>("fill-extrusion-opacity", function);
}
@@ -1070,6 +1569,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("fill-extrusion-color", value);
}
+ /**
+ * The base color of the extruded fill. The extrusion's surfaces will be shaded differently based on this color in combination with the root `light` settings. If this color is specified as `rgba` with an alpha component, the alpha component will be ignored; use {@link PropertyFactory#fillExtrusionOpacity} to set layer opacity.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> fillExtrusionColor(Expression expression) {
+ return new PaintPropertyValue<>("fill-extrusion-color", expression);
+ }
+
/**
* The base color of the extruded fill. The extrusion's surfaces will be shaded differently based on this color in combination with the root `light` settings. If this color is specified as `rgba` with an alpha component, the alpha component will be ignored; use {@link PropertyFactory#fillExtrusionOpacity} to set layer opacity.
@@ -1078,6 +1587,7 @@ public class PropertyFactory {
* @param function a wrapper function for String
* @return property wrapper around a String function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, String>> fillExtrusionColor(Function<T, String> function) {
return new PaintPropertyValue<>("fill-extrusion-color", function);
}
@@ -1092,6 +1602,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("fill-extrusion-translate", value);
}
+ /**
+ * The geometry's offset. Values are [x, y] where negatives indicate left and up (on the flat plane), respectively.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> fillExtrusionTranslate(Expression expression) {
+ return new PaintPropertyValue<>("fill-extrusion-translate", expression);
+ }
+
/**
* The geometry's offset. Values are [x, y] where negatives indicate left and up (on the flat plane), respectively.
@@ -1100,12 +1620,13 @@ public class PropertyFactory {
* @param function a wrapper {@link CameraFunction} for Float[]
* @return property wrapper around a Float[] function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, Float[]>> fillExtrusionTranslate(CameraFunction<Z, Float[]> function) {
return new PaintPropertyValue<>("fill-extrusion-translate", function);
}
/**
- * Controls the translation reference point.
+ * Controls the frame of reference for {@link PropertyFactory#fillExtrusionTranslate}.
*
* @param value a String value
* @return property wrapper around String
@@ -1114,14 +1635,25 @@ public class PropertyFactory {
return new PaintPropertyValue<>("fill-extrusion-translate-anchor", value);
}
+ /**
+ * Controls the frame of reference for {@link PropertyFactory#fillExtrusionTranslate}.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> fillExtrusionTranslateAnchor(Expression expression) {
+ return new PaintPropertyValue<>("fill-extrusion-translate-anchor", expression);
+ }
+
/**
- * Controls the translation reference point.
+ * Controls the frame of reference for {@link PropertyFactory#fillExtrusionTranslate}.
*
* @param <Z> the zoom parameter type
* @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> fillExtrusionTranslateAnchor(CameraFunction<Z, String> function) {
return new PaintPropertyValue<>("fill-extrusion-translate-anchor", function);
}
@@ -1136,6 +1668,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("fill-extrusion-pattern", value);
}
+ /**
+ * Name of image in sprite to use for drawing images on extruded fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512).
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> fillExtrusionPattern(Expression expression) {
+ return new PaintPropertyValue<>("fill-extrusion-pattern", expression);
+ }
+
/**
* Name of image in sprite to use for drawing images on extruded fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512).
@@ -1144,6 +1686,7 @@ public class PropertyFactory {
* @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> fillExtrusionPattern(CameraFunction<Z, String> function) {
return new PaintPropertyValue<>("fill-extrusion-pattern", function);
}
@@ -1158,6 +1701,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("fill-extrusion-height", value);
}
+ /**
+ * The height with which to extrude this layer.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> fillExtrusionHeight(Expression expression) {
+ return new PaintPropertyValue<>("fill-extrusion-height", expression);
+ }
+
/**
* The height with which to extrude this layer.
@@ -1166,6 +1719,7 @@ public class PropertyFactory {
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, Float>> fillExtrusionHeight(Function<T, Float> function) {
return new PaintPropertyValue<>("fill-extrusion-height", function);
}
@@ -1180,6 +1734,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("fill-extrusion-base", value);
}
+ /**
+ * The height with which to extrude the base of this layer. Must be less than or equal to {@link PropertyFactory#fillExtrusionHeight}.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> fillExtrusionBase(Expression expression) {
+ return new PaintPropertyValue<>("fill-extrusion-base", expression);
+ }
+
/**
* The height with which to extrude the base of this layer. Must be less than or equal to {@link PropertyFactory#fillExtrusionHeight}.
@@ -1188,6 +1752,7 @@ public class PropertyFactory {
* @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, Float>> fillExtrusionBase(Function<T, Float> function) {
return new PaintPropertyValue<>("fill-extrusion-base", function);
}
@@ -1202,6 +1767,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("raster-opacity", value);
}
+ /**
+ * The opacity at which the image will be drawn.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> rasterOpacity(Expression expression) {
+ return new PaintPropertyValue<>("raster-opacity", expression);
+ }
+
/**
* The opacity at which the image will be drawn.
@@ -1210,6 +1785,7 @@ public class PropertyFactory {
* @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> rasterOpacity(CameraFunction<Z, Float> function) {
return new PaintPropertyValue<>("raster-opacity", function);
}
@@ -1224,6 +1800,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("raster-hue-rotate", value);
}
+ /**
+ * Rotates hues around the color wheel.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> rasterHueRotate(Expression expression) {
+ return new PaintPropertyValue<>("raster-hue-rotate", expression);
+ }
+
/**
* Rotates hues around the color wheel.
@@ -1232,6 +1818,7 @@ public class PropertyFactory {
* @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> rasterHueRotate(CameraFunction<Z, Float> function) {
return new PaintPropertyValue<>("raster-hue-rotate", function);
}
@@ -1246,6 +1833,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("raster-brightness-min", value);
}
+ /**
+ * Increase or reduce the brightness of the image. The value is the minimum brightness.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> rasterBrightnessMin(Expression expression) {
+ return new PaintPropertyValue<>("raster-brightness-min", expression);
+ }
+
/**
* Increase or reduce the brightness of the image. The value is the minimum brightness.
@@ -1254,6 +1851,7 @@ public class PropertyFactory {
* @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> rasterBrightnessMin(CameraFunction<Z, Float> function) {
return new PaintPropertyValue<>("raster-brightness-min", function);
}
@@ -1268,6 +1866,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("raster-brightness-max", value);
}
+ /**
+ * Increase or reduce the brightness of the image. The value is the maximum brightness.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> rasterBrightnessMax(Expression expression) {
+ return new PaintPropertyValue<>("raster-brightness-max", expression);
+ }
+
/**
* Increase or reduce the brightness of the image. The value is the maximum brightness.
@@ -1276,6 +1884,7 @@ public class PropertyFactory {
* @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> rasterBrightnessMax(CameraFunction<Z, Float> function) {
return new PaintPropertyValue<>("raster-brightness-max", function);
}
@@ -1290,6 +1899,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("raster-saturation", value);
}
+ /**
+ * Increase or reduce the saturation of the image.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> rasterSaturation(Expression expression) {
+ return new PaintPropertyValue<>("raster-saturation", expression);
+ }
+
/**
* Increase or reduce the saturation of the image.
@@ -1298,6 +1917,7 @@ public class PropertyFactory {
* @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> rasterSaturation(CameraFunction<Z, Float> function) {
return new PaintPropertyValue<>("raster-saturation", function);
}
@@ -1312,6 +1932,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("raster-contrast", value);
}
+ /**
+ * Increase or reduce the contrast of the image.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> rasterContrast(Expression expression) {
+ return new PaintPropertyValue<>("raster-contrast", expression);
+ }
+
/**
* Increase or reduce the contrast of the image.
@@ -1320,6 +1950,7 @@ public class PropertyFactory {
* @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> rasterContrast(CameraFunction<Z, Float> function) {
return new PaintPropertyValue<>("raster-contrast", function);
}
@@ -1334,6 +1965,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("raster-fade-duration", value);
}
+ /**
+ * Fade duration when a new tile is added.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> rasterFadeDuration(Expression expression) {
+ return new PaintPropertyValue<>("raster-fade-duration", expression);
+ }
+
/**
* Fade duration when a new tile is added.
@@ -1342,6 +1983,7 @@ public class PropertyFactory {
* @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> rasterFadeDuration(CameraFunction<Z, Float> function) {
return new PaintPropertyValue<>("raster-fade-duration", function);
}
@@ -1366,6 +2008,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("background-color", value);
}
+ /**
+ * The color with which the background will be drawn.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> backgroundColor(Expression expression) {
+ return new PaintPropertyValue<>("background-color", expression);
+ }
+
/**
* The color with which the background will be drawn.
@@ -1374,6 +2026,7 @@ public class PropertyFactory {
* @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> backgroundColor(CameraFunction<Z, String> function) {
return new PaintPropertyValue<>("background-color", function);
}
@@ -1388,6 +2041,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("background-pattern", value);
}
+ /**
+ * Name of image in sprite to use for drawing an image background. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512).
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> backgroundPattern(Expression expression) {
+ return new PaintPropertyValue<>("background-pattern", expression);
+ }
+
/**
* Name of image in sprite to use for drawing an image background. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512).
@@ -1396,6 +2059,7 @@ public class PropertyFactory {
* @param function a wrapper {@link CameraFunction} for String
* @return property wrapper around a String function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> backgroundPattern(CameraFunction<Z, String> function) {
return new PaintPropertyValue<>("background-pattern", function);
}
@@ -1410,6 +2074,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("background-opacity", value);
}
+ /**
+ * The opacity at which the background will be drawn.
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> backgroundOpacity(Expression expression) {
+ return new PaintPropertyValue<>("background-opacity", expression);
+ }
+
/**
* The opacity at which the background will be drawn.
@@ -1418,6 +2092,7 @@ public class PropertyFactory {
* @param function a wrapper {@link CameraFunction} for Float
* @return property wrapper around a Float function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> backgroundOpacity(CameraFunction<Z, Float> function) {
return new PaintPropertyValue<>("background-opacity", function);
}
@@ -1432,6 +2107,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("line-cap", value);
}
+ /**
+ * The display of line endings.
+ *
+ * @param value a String value
+ * @return property wrapper around String
+ */
+ public static PropertyValue<Expression> lineCap(Expression value) {
+ return new LayoutPropertyValue<>("line-cap", value);
+ }
/**
@@ -1455,16 +2139,25 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("line-join", value);
}
+ /**
+ * The display of lines when joining.
+ *
+ * @param value a String value
+ * @return property wrapper around String
+ */
+ public static PropertyValue<Expression> lineJoin(Expression value) {
+ return new LayoutPropertyValue<>("line-join", value);
+ }
/**
* The display of lines when joining.
*
- * @param <Z> the zoom parameter type
- * @param function a wrapper {@link CameraFunction} for String
+ * @param <T> the function input type
+ * @param function a wrapper function for String
* @return property wrapper around a String function
*/
- public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> lineJoin(CameraFunction<Z, String> function) {
+ public static <T> PropertyValue<Function<T, String>> lineJoin(Function<T, String> function) {
return new LayoutPropertyValue<>("line-join", function);
}
@@ -1478,6 +2171,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("line-miter-limit", value);
}
+ /**
+ * Used to automatically convert miter joins to bevel joins for sharp angles.
+ *
+ * @param value a Float value
+ * @return property wrapper around Float
+ */
+ public static PropertyValue<Expression> lineMiterLimit(Expression value) {
+ return new LayoutPropertyValue<>("line-miter-limit", value);
+ }
/**
@@ -1501,6 +2203,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("line-round-limit", value);
}
+ /**
+ * Used to automatically convert round joins to miter joins for shallow angles.
+ *
+ * @param value a Float value
+ * @return property wrapper around Float
+ */
+ public static PropertyValue<Expression> lineRoundLimit(Expression value) {
+ return new LayoutPropertyValue<>("line-round-limit", value);
+ }
/**
@@ -1524,6 +2235,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("symbol-placement", value);
}
+ /**
+ * Label placement relative to its geometry.
+ *
+ * @param value a String value
+ * @return property wrapper around String
+ */
+ public static PropertyValue<Expression> symbolPlacement(Expression value) {
+ return new LayoutPropertyValue<>("symbol-placement", value);
+ }
/**
@@ -1547,6 +2267,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("symbol-spacing", value);
}
+ /**
+ * Distance between two symbol anchors.
+ *
+ * @param value a Float value
+ * @return property wrapper around Float
+ */
+ public static PropertyValue<Expression> symbolSpacing(Expression value) {
+ return new LayoutPropertyValue<>("symbol-spacing", value);
+ }
/**
@@ -1570,6 +2299,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("symbol-avoid-edges", value);
}
+ /**
+ * If true, the symbols will not cross tile edges to avoid mutual collisions. Recommended in layers that don't have enough padding in the vector tile to prevent collisions, or if it is a point symbol layer placed after a line symbol layer.
+ *
+ * @param value a Boolean value
+ * @return property wrapper around Boolean
+ */
+ public static PropertyValue<Expression> symbolAvoidEdges(Expression value) {
+ return new LayoutPropertyValue<>("symbol-avoid-edges", value);
+ }
/**
@@ -1593,6 +2331,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("icon-allow-overlap", value);
}
+ /**
+ * If true, the icon will be visible even if it collides with other previously drawn symbols.
+ *
+ * @param value a Boolean value
+ * @return property wrapper around Boolean
+ */
+ public static PropertyValue<Expression> iconAllowOverlap(Expression value) {
+ return new LayoutPropertyValue<>("icon-allow-overlap", value);
+ }
/**
@@ -1616,6 +2363,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("icon-ignore-placement", value);
}
+ /**
+ * If true, other symbols can be visible even if they collide with the icon.
+ *
+ * @param value a Boolean value
+ * @return property wrapper around Boolean
+ */
+ public static PropertyValue<Expression> iconIgnorePlacement(Expression value) {
+ return new LayoutPropertyValue<>("icon-ignore-placement", value);
+ }
/**
@@ -1639,6 +2395,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("icon-optional", value);
}
+ /**
+ * If true, text will display without their corresponding icons when the icon collides with other symbols and the text does not.
+ *
+ * @param value a Boolean value
+ * @return property wrapper around Boolean
+ */
+ public static PropertyValue<Expression> iconOptional(Expression value) {
+ return new LayoutPropertyValue<>("icon-optional", value);
+ }
/**
@@ -1662,6 +2427,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("icon-rotation-alignment", value);
}
+ /**
+ * In combination with {@link Property.SYMBOL_PLACEMENT}, determines the rotation behavior of icons.
+ *
+ * @param value a String value
+ * @return property wrapper around String
+ */
+ public static PropertyValue<Expression> iconRotationAlignment(Expression value) {
+ return new LayoutPropertyValue<>("icon-rotation-alignment", value);
+ }
/**
@@ -1685,6 +2459,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("icon-size", value);
}
+ /**
+ * Scales the original size of the icon by the provided factor. The new pixel size of the image will be the original pixel size multiplied by {@link PropertyFactory#iconSize}. 1 is the original size; 3 triples the size of the image.
+ *
+ * @param value a Float value
+ * @return property wrapper around Float
+ */
+ public static PropertyValue<Expression> iconSize(Expression value) {
+ return new LayoutPropertyValue<>("icon-size", value);
+ }
/**
@@ -1708,6 +2491,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("icon-text-fit", value);
}
+ /**
+ * Scales the icon to fit around the associated text.
+ *
+ * @param value a String value
+ * @return property wrapper around String
+ */
+ public static PropertyValue<Expression> iconTextFit(Expression value) {
+ return new LayoutPropertyValue<>("icon-text-fit", value);
+ }
/**
@@ -1731,6 +2523,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("icon-text-fit-padding", value);
}
+ /**
+ * Size of the additional area added to dimensions determined by {@link Property.ICON_TEXT_FIT}, in clockwise order: top, right, bottom, left.
+ *
+ * @param value a Float[] value
+ * @return property wrapper around Float[]
+ */
+ public static PropertyValue<Expression> iconTextFitPadding(Expression value) {
+ return new LayoutPropertyValue<>("icon-text-fit-padding", value);
+ }
/**
@@ -1745,7 +2546,7 @@ public class PropertyFactory {
}
/**
- * Name of image in sprite to use for drawing an image background. A string with {tokens} replaced, referencing the data property to pull from.
+ * Name of image in sprite to use for drawing an image background. A string with `{tokens}` replaced, referencing the data property to pull from. (`{token}` replacement is only supported for literal {@link PropertyFactory#iconImage} values; not for property functions.)
*
* @param value a String value
* @return property wrapper around String
@@ -1754,10 +2555,19 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("icon-image", value);
}
+ /**
+ * Name of image in sprite to use for drawing an image background. A string with `{tokens}` replaced, referencing the data property to pull from. (`{token}` replacement is only supported for literal {@link PropertyFactory#iconImage} values; not for property functions.)
+ *
+ * @param value a String value
+ * @return property wrapper around String
+ */
+ public static PropertyValue<Expression> iconImage(Expression value) {
+ return new LayoutPropertyValue<>("icon-image", value);
+ }
/**
- * Name of image in sprite to use for drawing an image background. A string with {tokens} replaced, referencing the data property to pull from.
+ * Name of image in sprite to use for drawing an image background. A string with `{tokens}` replaced, referencing the data property to pull from. (`{token}` replacement is only supported for literal {@link PropertyFactory#iconImage} values; not for property functions.)
*
* @param <T> the function input type
* @param function a wrapper function for String
@@ -1777,6 +2587,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("icon-rotate", value);
}
+ /**
+ * Rotates the icon clockwise.
+ *
+ * @param value a Float value
+ * @return property wrapper around Float
+ */
+ public static PropertyValue<Expression> iconRotate(Expression value) {
+ return new LayoutPropertyValue<>("icon-rotate", value);
+ }
/**
@@ -1800,6 +2619,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("icon-padding", value);
}
+ /**
+ * Size of the additional area around the icon bounding box used for detecting symbol collisions.
+ *
+ * @param value a Float value
+ * @return property wrapper around Float
+ */
+ public static PropertyValue<Expression> iconPadding(Expression value) {
+ return new LayoutPropertyValue<>("icon-padding", value);
+ }
/**
@@ -1823,6 +2651,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("icon-keep-upright", value);
}
+ /**
+ * If true, the icon may be flipped to prevent it from being rendered upside-down.
+ *
+ * @param value a Boolean value
+ * @return property wrapper around Boolean
+ */
+ public static PropertyValue<Expression> iconKeepUpright(Expression value) {
+ return new LayoutPropertyValue<>("icon-keep-upright", value);
+ }
/**
@@ -1846,6 +2683,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("icon-offset", value);
}
+ /**
+ * Offset distance of icon from its anchor. Positive values indicate right and down, while negative values indicate left and up. When combined with {@link PropertyFactory#iconRotate} the offset will be as if the rotated direction was up.
+ *
+ * @param value a Float[] value
+ * @return property wrapper around Float[]
+ */
+ public static PropertyValue<Expression> iconOffset(Expression value) {
+ return new LayoutPropertyValue<>("icon-offset", value);
+ }
/**
@@ -1860,6 +2706,70 @@ public class PropertyFactory {
}
/**
+ * Part of the icon placed closest to the anchor.
+ *
+ * @param value a String value
+ * @return property wrapper around String
+ */
+ public static PropertyValue<String> iconAnchor(@Property.ICON_ANCHOR String value) {
+ return new LayoutPropertyValue<>("icon-anchor", value);
+ }
+
+ /**
+ * Part of the icon placed closest to the anchor.
+ *
+ * @param value a String value
+ * @return property wrapper around String
+ */
+ public static PropertyValue<Expression> iconAnchor(Expression value) {
+ return new LayoutPropertyValue<>("icon-anchor", value);
+ }
+
+
+ /**
+ * Part of the icon placed closest to the anchor.
+ *
+ * @param <T> the function input type
+ * @param function a wrapper function for String
+ * @return property wrapper around a String function
+ */
+ public static <T> PropertyValue<Function<T, String>> iconAnchor(Function<T, String> function) {
+ return new LayoutPropertyValue<>("icon-anchor", function);
+ }
+
+ /**
+ * Orientation of icon when map is pitched.
+ *
+ * @param value a String value
+ * @return property wrapper around String
+ */
+ public static PropertyValue<String> iconPitchAlignment(@Property.ICON_PITCH_ALIGNMENT String value) {
+ return new LayoutPropertyValue<>("icon-pitch-alignment", value);
+ }
+
+ /**
+ * Orientation of icon when map is pitched.
+ *
+ * @param value a String value
+ * @return property wrapper around String
+ */
+ public static PropertyValue<Expression> iconPitchAlignment(Expression value) {
+ return new LayoutPropertyValue<>("icon-pitch-alignment", value);
+ }
+
+
+ /**
+ * Orientation of icon when map is pitched.
+ *
+ * @param <Z> the zoom parameter type
+ * @param function a wrapper {@link CameraFunction} for String
+ * @return property wrapper around a String function
+ */
+ public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> iconPitchAlignment(CameraFunction<Z, String> function) {
+ return new LayoutPropertyValue<>("icon-pitch-alignment", function);
+ }
+
+ /**
* Orientation of text when map is pitched.
*
* @param value a String value
@@ -1869,6 +2779,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("text-pitch-alignment", value);
}
+ /**
+ * Orientation of text when map is pitched.
+ *
+ * @param value a String value
+ * @return property wrapper around String
+ */
+ public static PropertyValue<Expression> textPitchAlignment(Expression value) {
+ return new LayoutPropertyValue<>("text-pitch-alignment", value);
+ }
/**
@@ -1892,6 +2811,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("text-rotation-alignment", value);
}
+ /**
+ * In combination with {@link Property.SYMBOL_PLACEMENT}, determines the rotation behavior of the individual glyphs forming the text.
+ *
+ * @param value a String value
+ * @return property wrapper around String
+ */
+ public static PropertyValue<Expression> textRotationAlignment(Expression value) {
+ return new LayoutPropertyValue<>("text-rotation-alignment", value);
+ }
/**
@@ -1906,7 +2834,7 @@ public class PropertyFactory {
}
/**
- * Value to use for a text label. Feature properties are specified using tokens like {field_name}. (Token replacement is only supported for literal {@link PropertyFactory#textField} values--not for property functions.)
+ * Value to use for a text label. Feature properties are specified using tokens like `{field_name}`. (`{token}` replacement is only supported for literal {@link PropertyFactory#textField} values; not for property functions.)
*
* @param value a String value
* @return property wrapper around String
@@ -1915,10 +2843,19 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("text-field", value);
}
+ /**
+ * Value to use for a text label. Feature properties are specified using tokens like `{field_name}`. (`{token}` replacement is only supported for literal {@link PropertyFactory#textField} values; not for property functions.)
+ *
+ * @param value a String value
+ * @return property wrapper around String
+ */
+ public static PropertyValue<Expression> textField(Expression value) {
+ return new LayoutPropertyValue<>("text-field", value);
+ }
/**
- * Value to use for a text label. Feature properties are specified using tokens like {field_name}. (Token replacement is only supported for literal {@link PropertyFactory#textField} values--not for property functions.)
+ * Value to use for a text label. Feature properties are specified using tokens like `{field_name}`. (`{token}` replacement is only supported for literal {@link PropertyFactory#textField} values; not for property functions.)
*
* @param <T> the function input type
* @param function a wrapper function for String
@@ -1938,16 +2875,25 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("text-font", value);
}
+ /**
+ * Font stack to use for displaying text.
+ *
+ * @param value a String[] value
+ * @return property wrapper around String[]
+ */
+ public static PropertyValue<Expression> textFont(Expression value) {
+ return new LayoutPropertyValue<>("text-font", value);
+ }
/**
* Font stack to use for displaying text.
*
- * @param <Z> the zoom parameter type
- * @param function a wrapper {@link CameraFunction} for String[]
+ * @param <T> the function input type
+ * @param function a wrapper function for String[]
* @return property wrapper around a String[] function
*/
- public static <Z extends Number> PropertyValue<CameraFunction<Z, String[]>> textFont(CameraFunction<Z, String[]> function) {
+ public static <T> PropertyValue<Function<T, String[]>> textFont(Function<T, String[]> function) {
return new LayoutPropertyValue<>("text-font", function);
}
@@ -1961,6 +2907,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("text-size", value);
}
+ /**
+ * Font size.
+ *
+ * @param value a Float value
+ * @return property wrapper around Float
+ */
+ public static PropertyValue<Expression> textSize(Expression value) {
+ return new LayoutPropertyValue<>("text-size", value);
+ }
/**
@@ -1984,16 +2939,25 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("text-max-width", value);
}
+ /**
+ * The maximum line width for text wrapping.
+ *
+ * @param value a Float value
+ * @return property wrapper around Float
+ */
+ public static PropertyValue<Expression> textMaxWidth(Expression value) {
+ return new LayoutPropertyValue<>("text-max-width", value);
+ }
/**
* The maximum line width for text wrapping.
*
- * @param <Z> the zoom parameter type
- * @param function a wrapper {@link CameraFunction} for Float
+ * @param <T> the function input type
+ * @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
- public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> textMaxWidth(CameraFunction<Z, Float> function) {
+ public static <T> PropertyValue<Function<T, Float>> textMaxWidth(Function<T, Float> function) {
return new LayoutPropertyValue<>("text-max-width", function);
}
@@ -2007,6 +2971,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("text-line-height", value);
}
+ /**
+ * Text leading value for multi-line text.
+ *
+ * @param value a Float value
+ * @return property wrapper around Float
+ */
+ public static PropertyValue<Expression> textLineHeight(Expression value) {
+ return new LayoutPropertyValue<>("text-line-height", value);
+ }
/**
@@ -2030,16 +3003,25 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("text-letter-spacing", value);
}
+ /**
+ * Text tracking amount.
+ *
+ * @param value a Float value
+ * @return property wrapper around Float
+ */
+ public static PropertyValue<Expression> textLetterSpacing(Expression value) {
+ return new LayoutPropertyValue<>("text-letter-spacing", value);
+ }
/**
* Text tracking amount.
*
- * @param <Z> the zoom parameter type
- * @param function a wrapper {@link CameraFunction} for Float
+ * @param <T> the function input type
+ * @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
- public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> textLetterSpacing(CameraFunction<Z, Float> function) {
+ public static <T> PropertyValue<Function<T, Float>> textLetterSpacing(Function<T, Float> function) {
return new LayoutPropertyValue<>("text-letter-spacing", function);
}
@@ -2053,16 +3035,25 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("text-justify", value);
}
+ /**
+ * Text justification options.
+ *
+ * @param value a String value
+ * @return property wrapper around String
+ */
+ public static PropertyValue<Expression> textJustify(Expression value) {
+ return new LayoutPropertyValue<>("text-justify", value);
+ }
/**
* Text justification options.
*
- * @param <Z> the zoom parameter type
- * @param function a wrapper {@link CameraFunction} for String
+ * @param <T> the function input type
+ * @param function a wrapper function for String
* @return property wrapper around a String function
*/
- public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> textJustify(CameraFunction<Z, String> function) {
+ public static <T> PropertyValue<Function<T, String>> textJustify(Function<T, String> function) {
return new LayoutPropertyValue<>("text-justify", function);
}
@@ -2076,16 +3067,25 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("text-anchor", value);
}
+ /**
+ * Part of the text placed closest to the anchor.
+ *
+ * @param value a String value
+ * @return property wrapper around String
+ */
+ public static PropertyValue<Expression> textAnchor(Expression value) {
+ return new LayoutPropertyValue<>("text-anchor", value);
+ }
/**
* Part of the text placed closest to the anchor.
*
- * @param <Z> the zoom parameter type
- * @param function a wrapper {@link CameraFunction} for String
+ * @param <T> the function input type
+ * @param function a wrapper function for String
* @return property wrapper around a String function
*/
- public static <Z extends Number> PropertyValue<CameraFunction<Z, String>> textAnchor(CameraFunction<Z, String> function) {
+ public static <T> PropertyValue<Function<T, String>> textAnchor(Function<T, String> function) {
return new LayoutPropertyValue<>("text-anchor", function);
}
@@ -2099,6 +3099,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("text-max-angle", value);
}
+ /**
+ * Maximum angle change between adjacent characters.
+ *
+ * @param value a Float value
+ * @return property wrapper around Float
+ */
+ public static PropertyValue<Expression> textMaxAngle(Expression value) {
+ return new LayoutPropertyValue<>("text-max-angle", value);
+ }
/**
@@ -2122,6 +3131,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("text-rotate", value);
}
+ /**
+ * Rotates the text clockwise.
+ *
+ * @param value a Float value
+ * @return property wrapper around Float
+ */
+ public static PropertyValue<Expression> textRotate(Expression value) {
+ return new LayoutPropertyValue<>("text-rotate", value);
+ }
/**
@@ -2145,6 +3163,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("text-padding", value);
}
+ /**
+ * Size of the additional area around the text bounding box used for detecting symbol collisions.
+ *
+ * @param value a Float value
+ * @return property wrapper around Float
+ */
+ public static PropertyValue<Expression> textPadding(Expression value) {
+ return new LayoutPropertyValue<>("text-padding", value);
+ }
/**
@@ -2168,6 +3195,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("text-keep-upright", value);
}
+ /**
+ * If true, the text may be flipped vertically to prevent it from being rendered upside-down.
+ *
+ * @param value a Boolean value
+ * @return property wrapper around Boolean
+ */
+ public static PropertyValue<Expression> textKeepUpright(Expression value) {
+ return new LayoutPropertyValue<>("text-keep-upright", value);
+ }
/**
@@ -2191,6 +3227,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("text-transform", value);
}
+ /**
+ * Specifies how to capitalize text, similar to the CSS {@link PropertyFactory#textTransform} property.
+ *
+ * @param value a String value
+ * @return property wrapper around String
+ */
+ public static PropertyValue<Expression> textTransform(Expression value) {
+ return new LayoutPropertyValue<>("text-transform", value);
+ }
/**
@@ -2214,6 +3259,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("text-offset", value);
}
+ /**
+ * Offset distance of text from its anchor. Positive values indicate right and down, while negative values indicate left and up.
+ *
+ * @param value a Float[] value
+ * @return property wrapper around Float[]
+ */
+ public static PropertyValue<Expression> textOffset(Expression value) {
+ return new LayoutPropertyValue<>("text-offset", value);
+ }
/**
@@ -2237,6 +3291,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("text-allow-overlap", value);
}
+ /**
+ * If true, the text will be visible even if it collides with other previously drawn symbols.
+ *
+ * @param value a Boolean value
+ * @return property wrapper around Boolean
+ */
+ public static PropertyValue<Expression> textAllowOverlap(Expression value) {
+ return new LayoutPropertyValue<>("text-allow-overlap", value);
+ }
/**
@@ -2260,6 +3323,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("text-ignore-placement", value);
}
+ /**
+ * If true, other symbols can be visible even if they collide with the text.
+ *
+ * @param value a Boolean value
+ * @return property wrapper around Boolean
+ */
+ public static PropertyValue<Expression> textIgnorePlacement(Expression value) {
+ return new LayoutPropertyValue<>("text-ignore-placement", value);
+ }
/**
@@ -2283,7 +3355,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("text-optional", value);
}
-
+ /**
+ * If true, icons will display without their corresponding text when the text collides with other symbols and the icon does not.
+ *
+ * @param value a Boolean value
+ * @return property wrapper around Boolean
+ */
+ public static PropertyValue<Expression> textOptional(Expression value) {
+ return new LayoutPropertyValue<>("text-optional", value);
+ }
/**
* If true, icons will display without their corresponding text when the text collides with other symbols and the icon does not.
@@ -2296,9 +3376,9 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("text-optional", function);
}
- @SuppressLint("DefaultLocale")
public static String colorToRgbaString(@ColorInt int value) {
- return String.format("rgba(%d, %d, %d, %d)", (value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF, (value >> 24) & 0xFF);
+ return String.format(Locale.US,"rgba(%d, %d, %d, %d)",
+ (value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF, (value >> 24) & 0xFF);
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java
index 68727c8a4f..a57c440df4 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java
@@ -30,14 +30,29 @@ public class PropertyValue<T> {
this.value = value;
}
+ /**
+ * Returns if this is null
+ *
+ * @return true if this is null, false if not
+ */
public boolean isNull() {
return value == null;
}
+ /**
+ * Returns if this is a function.
+ *
+ * @return true if is a function, false if not
+ */
public boolean isFunction() {
return !isNull() && value instanceof Function;
}
+ /**
+ * Returns if this is a value.
+ *
+ * @return true if is a value, false if not
+ */
public boolean isValue() {
return !isNull() && !isFunction();
}
@@ -53,6 +68,11 @@ public class PropertyValue<T> {
}
}
+ /**
+ * Get the value of the property.
+ *
+ * @return the property value
+ */
@Nullable
public T getValue() {
if (isValue()) {
@@ -64,6 +84,11 @@ public class PropertyValue<T> {
}
}
+ /**
+ * Get the color int value of the property if the value is a color.
+ *
+ * @return the color int value of the property, null if not a color value
+ */
@ColorInt
@Nullable
public Integer getColorInt() {
@@ -80,6 +105,11 @@ public class PropertyValue<T> {
}
}
+ /**
+ * Get the string representation of a property value.
+ *
+ * @return the string representation
+ */
@Override
public String toString() {
return String.format("%s: %s", name, value);
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java
index e67e71b61d..0a056d8fac 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java
@@ -2,14 +2,9 @@
package com.mapbox.mapboxsdk.style.layers;
-import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.UiThread;
-import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor;
-
-import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
-
/**
* Raster map textures such as satellite imagery.
*
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java
index 290e162da8..3d2c3881b2 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java
@@ -8,8 +8,6 @@ import android.support.annotation.UiThread;
import static com.mapbox.mapboxsdk.utils.ColorUtils.rgbaToColor;
-import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
-
/**
* An icon or a text label.
*
@@ -252,6 +250,26 @@ public class SymbolLayer extends Layer {
}
/**
+ * Get the IconAnchor property
+ *
+ * @return property wrapper value around String
+ */
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getIconAnchor() {
+ return (PropertyValue<String>) new PropertyValue("icon-anchor", nativeGetIconAnchor());
+ }
+
+ /**
+ * Get the IconPitchAlignment property
+ *
+ * @return property wrapper value around String
+ */
+ @SuppressWarnings("unchecked")
+ public PropertyValue<String> getIconPitchAlignment() {
+ return (PropertyValue<String>) new PropertyValue("icon-pitch-alignment", nativeGetIconPitchAlignment());
+ }
+
+ /**
* Get the TextPitchAlignment property
*
* @return property wrapper value around String
@@ -891,6 +909,10 @@ public class SymbolLayer extends Layer {
private native Object nativeGetIconOffset();
+ private native Object nativeGetIconAnchor();
+
+ private native Object nativeGetIconPitchAlignment();
+
private native Object nativeGetTextPitchAlignment();
private native Object nativeGetTextRotationAlignment();
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs
index 2d3421d1d9..ed138e557a 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/property_factory.java.ejs
@@ -11,6 +11,7 @@ import android.support.annotation.ColorInt;
import com.mapbox.mapboxsdk.style.functions.Function;
import com.mapbox.mapboxsdk.style.functions.CameraFunction;
+import com.mapbox.mapboxsdk.style.expressions.Expression;
/**
* Constructs paint/layout properties for Layers
@@ -36,6 +37,7 @@ public class PropertyFactory {
* @param function the visibility function
* @return property wrapper around a String function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, String>> visibility(Function<T, String> function) {
return new LayoutPropertyValue<>("visibility", function);
}
@@ -63,6 +65,16 @@ public class PropertyFactory {
return new PaintPropertyValue<>("<%- property.name %>", value);
}
+ /**
+ * <%- propertyFactoryMethodDoc(property) %>
+ *
+ * @param expression an expression statement
+ * @return property wrapper around an expression statement
+ */
+ public static PropertyValue<Expression> <%- camelizeWithLeadingLowercase(property.name) %>(Expression expression) {
+ return new PaintPropertyValue<>("<%- property.name %>", expression);
+ }
+
<% if (supportsPropertyFunction(property)) { -%>
/**
@@ -72,6 +84,7 @@ public class PropertyFactory {
* @param function a wrapper function for <%- propertyType(property) %>
* @return property wrapper around a <%- propertyType(property) %> function
*/
+ @Deprecated
public static <T> PropertyValue<Function<T, <%- propertyType(property) %>>> <%- camelizeWithLeadingLowercase(property.name) %>(Function<T, <%- propertyType(property) %>> function) {
return new PaintPropertyValue<>("<%- property.name %>", function);
}
@@ -85,6 +98,7 @@ public class PropertyFactory {
* @param function a wrapper {@link CameraFunction} for <%- propertyType(property) %>
* @return property wrapper around a <%- propertyType(property) %> function
*/
+ @Deprecated
public static <Z extends Number> PropertyValue<CameraFunction<Z, <%- propertyType(property) %>>> <%- camelizeWithLeadingLowercase(property.name) %>(CameraFunction<Z, <%- propertyType(property) %>> function) {
return new PaintPropertyValue<>("<%- property.name %>", function);
}
@@ -102,6 +116,15 @@ public class PropertyFactory {
return new LayoutPropertyValue<>("<%- property.name %>", value);
}
+ /**
+ * <%- propertyFactoryMethodDoc(property) %>
+ *
+ * @param value a <%- propertyType(property) %> value
+ * @return property wrapper around <%- propertyType(property) %>
+ */
+ public static PropertyValue<Expression> <%- camelizeWithLeadingLowercase(property.name) %>(Expression value) {
+ return new LayoutPropertyValue<>("<%- property.name %>", value);
+ }
<% if (supportsPropertyFunction(property)) { -%>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java
index b66a50b8a4..8f23e7d01e 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java
@@ -13,7 +13,7 @@ import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
/**
* The global light source.
*
- * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#light>">The online documentation</a>
+ * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#light">The online documentation</a>
*/
@UiThread
public class Light {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Position.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Position.java
index 215db03ad2..cd6218d3e2 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Position.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Position.java
@@ -18,7 +18,7 @@ public class Position {
private float polarAngle;
/**
- * Creates a Position from a radial coordinate, an azimuthal angle & a polar angle.
+ * Creates a Position from a radial coordinate, an azimuthal angle and a polar angle.
*
* @param radialCoordinate the distance from the center of the base of an object to its light
* @param azimuthalAngle the position of the light relative to 0°
@@ -31,7 +31,7 @@ public class Position {
}
/**
- * Returns a Position from a radial coordinate, an azimuthal angle & a polar angle
+ * Returns a Position from a radial coordinate, an azimuthal angle and a polar angle
*
* @param radialCoordinate the radial coordinate
* @param azimuthalAngle the azimuthal angle
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs
index 067efe1092..80d927128d 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs
@@ -17,7 +17,7 @@ import com.mapbox.mapboxsdk.style.layers.TransitionOptions;
/**
* The global light source.
*
- * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#light>">The online documentation</a>
+ * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#light">The online documentation</a>
*/
@UiThread
public class Light {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CustomGeometrySource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CustomGeometrySource.java
new file mode 100644
index 0000000000..62f1719ddf
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CustomGeometrySource.java
@@ -0,0 +1,203 @@
+package com.mapbox.mapboxsdk.style.sources;
+
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.UiThread;
+import android.support.annotation.WorkerThread;
+
+import com.mapbox.mapboxsdk.geometry.LatLngBounds;
+import com.mapbox.mapboxsdk.style.layers.Filter;
+import com.mapbox.services.commons.geojson.Feature;
+import com.mapbox.services.commons.geojson.FeatureCollection;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Custom Vector Source, allows using FeatureCollections.
+ *
+ */
+@UiThread
+public class CustomGeometrySource extends Source {
+ private ExecutorService executor;
+ private GeometryTileProvider provider;
+ private final Map<TileID, AtomicBoolean> cancelledTileRequests = new ConcurrentHashMap<>();
+
+ /**
+ * Create a CustomGeometrySource
+ *
+ * @param id The source id.
+ * @param provider The tile provider that returns geometry data for this source.
+ */
+ public CustomGeometrySource(String id, GeometryTileProvider provider) {
+ this(id, provider, new GeoJsonOptions());
+ }
+
+ /**
+ * Create a CustomGeometrySource with non-default GeoJsonOptions.
+ * <p>Supported options are minZoom, maxZoom, buffer, and tolerance.</p>
+ *
+ * @param id The source id.
+ * @param provider The tile provider that returns geometry data for this source.
+ * @param options GeoJsonOptions.
+ */
+ public CustomGeometrySource(String id, GeometryTileProvider provider, GeoJsonOptions options) {
+ this.provider = provider;
+ executor = Executors.newFixedThreadPool(4);
+ initialize(id, options);
+ }
+
+ /**
+ * Invalidate previously provided features within a given bounds at all zoom levels.
+ * Invoking this method will result in new requests to `GeometryTileProvider` for regions
+ * that contain, include, or intersect with the provided bounds.
+ *
+ * @param bounds The region in which features should be invalidated at all zoom levels
+ */
+ public void invalidateRegion(LatLngBounds bounds) {
+ nativeInvalidateBounds(bounds);
+ }
+
+ /**
+ * Invalidate the geometry contents of a specific tile. Invoking this method will result
+ * in new requests to `GeometryTileProvider` for visible tiles.
+ *
+ * @param zoomLevel Tile zoom level.
+ * @param x Tile X coordinate.
+ * @param y Tile Y coordinate.
+ */
+ public void invalidateTile(int zoomLevel, int x, int y) {
+ nativeInvalidateTile(zoomLevel, x, y);
+ }
+
+ /**
+ * Set or update geometry contents of a specific tile. Use this method to update tiles
+ * for which `GeometryTileProvider` was previously invoked. This method can be called from
+ * background threads.
+ *
+ * @param zoomLevel Tile zoom level.
+ * @param x Tile X coordinate.
+ * @param y Tile Y coordinate.
+ * @param data Feature collection for the tile.
+ */
+ public void setTileData(int zoomLevel, int x, int y, FeatureCollection data) {
+ nativeSetTileData(zoomLevel, x, y, data);
+ }
+
+ /**
+ * Queries the source for features.
+ *
+ * @param filter an optional filter statement to filter the returned Features
+ * @return the features
+ */
+ @NonNull
+ public List<Feature> querySourceFeatures(@Nullable Filter.Statement filter) {
+ Feature[] features = querySourceFeatures(filter != null ? filter.toArray() : null);
+ return features != null ? Arrays.asList(features) : new ArrayList<Feature>();
+ }
+
+ protected native void initialize(String sourceId, Object options);
+
+ private native Feature[] querySourceFeatures(Object[] filter);
+
+ private native void nativeSetTileData(int z, int x, int y, FeatureCollection data);
+
+ private native void nativeInvalidateTile(int z, int x, int y);
+
+ private native void nativeInvalidateBounds(LatLngBounds bounds);
+
+ @Override
+ protected native void finalize() throws Throwable;
+
+ private void setTileData(TileID tileId, FeatureCollection data) {
+ cancelledTileRequests.remove(tileId);
+ nativeSetTileData(tileId.z, tileId.x, tileId.y, data);
+ }
+
+ @WorkerThread
+ private void fetchTile(int z, int x, int y) {
+ AtomicBoolean cancelFlag = new AtomicBoolean(false);
+ TileID tileID = new TileID(z, x, y);
+ cancelledTileRequests.put(tileID, cancelFlag);
+ GeometryTileRequest request = new GeometryTileRequest(tileID, provider, this, cancelFlag);
+ executor.execute(request);
+ }
+
+ @WorkerThread
+ private void cancelTile(int z, int x, int y) {
+ AtomicBoolean cancelFlag = cancelledTileRequests.get(new TileID(z, x, y));
+ if (cancelFlag != null) {
+ cancelFlag.compareAndSet(false, true);
+ }
+ }
+
+ private static class TileID {
+ public int z;
+ public int x;
+ public int y;
+
+ public TileID(int _z, int _x, int _y) {
+ z = _z;
+ x = _x;
+ y = _y;
+ }
+
+ public int hashCode() {
+ return Arrays.hashCode(new int[]{z, x, y});
+ }
+
+ public boolean equals(Object object) {
+ if (object == this) {
+ return true;
+ }
+
+ if (object == null || getClass() != object.getClass()) {
+ return false;
+ }
+
+ if (object instanceof TileID) {
+ TileID other = (TileID)object;
+ return this.z == other.z && this.x == other.x && this.y == other.y;
+ }
+ return false;
+ }
+ }
+
+ private static class GeometryTileRequest implements Runnable {
+ private TileID id;
+ private GeometryTileProvider provider;
+ private WeakReference<CustomGeometrySource> sourceRef;
+ private AtomicBoolean cancelled;
+
+ public GeometryTileRequest(TileID _id, GeometryTileProvider p,
+ CustomGeometrySource _source, AtomicBoolean _cancelled) {
+ id = _id;
+ provider = p;
+ sourceRef = new WeakReference<>(_source);
+ cancelled = _cancelled;
+ }
+
+ public void run() {
+ if (isCancelled()) {
+ return;
+ }
+
+ FeatureCollection data = provider.getFeaturesForBounds(LatLngBounds.from(id.z, id.x, id.y), id.z);
+ CustomGeometrySource source = sourceRef.get();
+ if (!isCancelled() && source != null && data != null) {
+ source.setTileData(id, data);
+ }
+ }
+
+ private Boolean isCancelled() {
+ return cancelled.get();
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java
index 1a1711e547..81f7255b86 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java
@@ -16,6 +16,17 @@ public class GeoJsonOptions extends HashMap<String, Object> {
* @param maxZoom the maximum zoom - Defaults to 18.
* @return the current instance for chaining
*/
+ public GeoJsonOptions withMinZoom(int minZoom) {
+ this.put("minzoom", minZoom);
+ return this;
+ }
+
+ /**
+ * Maximum zoom level at which to create vector tiles (higher means greater detail at high zoom levels).
+ *
+ * @param maxZoom the maximum zoom - Defaults to 18.
+ * @return the current instance for chaining
+ */
public GeoJsonOptions withMaxZoom(int maxZoom) {
this.put("maxzoom", maxZoom);
return this;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeometryTileProvider.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeometryTileProvider.java
new file mode 100644
index 0000000000..3f1eb315d3
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeometryTileProvider.java
@@ -0,0 +1,22 @@
+package com.mapbox.mapboxsdk.style.sources;
+
+import android.support.annotation.WorkerThread;
+
+import com.mapbox.mapboxsdk.geometry.LatLngBounds;
+import com.mapbox.services.commons.geojson.FeatureCollection;
+
+/**
+ * Interface that defines methods for working with {@link CustomGeometrySource}.
+ */
+public interface GeometryTileProvider {
+
+ /***
+ * Interface method called by {@link CustomGeometrySource} to request features for a tile.
+ *
+ * @param bounds {@link LatLngBounds} of the tile.
+ * @param zoomLevel Tile zoom level.
+ * @return Return a @{link FeatureCollection} to be displayed in the requested tile.
+ */
+ @WorkerThread
+ FeatureCollection getFeaturesForBounds(LatLngBounds bounds, int zoomLevel);
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/text/LocalGlyphRasterizer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/text/LocalGlyphRasterizer.java
new file mode 100644
index 0000000000..920a1270ac
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/text/LocalGlyphRasterizer.java
@@ -0,0 +1,46 @@
+package com.mapbox.mapboxsdk.text;
+
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Bitmap;
+import android.graphics.Typeface;
+import android.support.annotation.WorkerThread;
+
+/**
+ * LocalGlyphRasterizer is the Android-specific platform implementation used
+ * by the portable local_glyph_rasterizer.hpp
+ */
+public class LocalGlyphRasterizer {
+
+ /***
+ * Uses Android-native drawing code to rasterize a single glyph
+ * to a square @{link Bitmap} which can be returned to portable
+ * code for transformation into a Signed Distance Field glyph.
+ *
+ * @param fontFamily Font family string to pass to Typeface.create
+ * @param bold If true, use Typeface.BOLD option
+ * @param glyphID 16-bit Unicode BMP codepoint to draw
+ *
+ * @return Return a @{link Bitmap} to be displayed in the requested tile.
+ */
+ @WorkerThread
+ protected static Bitmap drawGlyphBitmap(String fontFamily, boolean bold, char glyphID) {
+ /*
+ 35x35px dimensions are hardwired to match local_glyph_rasterizer.cpp
+ These dimensions are large enough to draw a 24 point character in the middle
+ of the bitmap (y: 20) with some buffer around the edge
+ */
+ Bitmap bitmap = Bitmap.createBitmap(35, 35, Bitmap.Config.ARGB_8888);
+
+ Paint paint = new Paint();
+ paint.setAntiAlias(true);
+ paint.setTextSize(24);
+ paint.setTypeface(Typeface.create(fontFamily, bold ? Typeface.BOLD : Typeface.NORMAL));
+
+ Canvas canvas = new Canvas();
+ canvas.setBitmap(bitmap);
+ canvas.drawText(String.valueOf(glyphID), 0, 20, paint);
+
+ return bitmap;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/BitmapUtils.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/BitmapUtils.java
index e3fc765734..78503f9dfe 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/BitmapUtils.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/BitmapUtils.java
@@ -1,12 +1,27 @@
package com.mapbox.mapboxsdk.utils;
+import android.content.Context;
import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.view.View;
+import java.io.ByteArrayOutputStream;
+
+/**
+ * Utility class for creating bitmaps
+ */
public class BitmapUtils {
+ /**
+ * Convert a view to a bitmap.
+ *
+ * @param view the view to convert
+ * @return the converted bitmap
+ */
public static Bitmap createBitmapFromView(@NonNull View view) {
view.setDrawingCacheEnabled(true);
view.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_LOW);
@@ -22,6 +37,13 @@ public class BitmapUtils {
return snapshot;
}
+ /**
+ * Create a bitmap from a background and a foreground bitmap
+ *
+ * @param background The bitmap placed in the background
+ * @param foreground The bitmap placed in the foreground
+ * @return the merged bitmap
+ */
public static Bitmap mergeBitmap(@NonNull Bitmap background, @NonNull Bitmap foreground) {
Bitmap result = Bitmap.createBitmap(background.getWidth(), background.getHeight(), background.getConfig());
Canvas canvas = new Canvas(result);
@@ -30,4 +52,69 @@ public class BitmapUtils {
return result;
}
+ /**
+ * Extract an underlying bitmap from a drawable
+ *
+ * @param sourceDrawable The source drawable
+ * @return The underlying bitmap
+ */
+ public static Bitmap getBitmapFromDrawable(Drawable sourceDrawable) {
+ if (sourceDrawable == null) {
+ return null;
+ }
+
+ if (sourceDrawable instanceof BitmapDrawable) {
+ return ((BitmapDrawable) sourceDrawable).getBitmap();
+ } else {
+ //copying drawable object to not manipulate on the same reference
+ Drawable.ConstantState constantState = sourceDrawable.getConstantState();
+ if (constantState == null) {
+ return null;
+ }
+ Drawable drawable = constantState.newDrawable().mutate();
+
+ Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(),
+ Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+ drawable.draw(canvas);
+ return bitmap;
+ }
+ }
+
+ /**
+ * Create a byte array out of drawable
+ *
+ * @param drawable The source drawable
+ * @return The byte array of source drawable
+ */
+ public static byte[] getByteArrayFromDrawable(Drawable drawable) {
+ if (drawable == null) {
+ return null;
+ }
+
+ Bitmap bitmap = getBitmapFromDrawable(drawable);
+ if (bitmap == null) {
+ return null;
+ }
+ ByteArrayOutputStream stream = new ByteArrayOutputStream();
+ bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
+ return stream.toByteArray();
+ }
+
+ /**
+ * Decode byte array to drawable object
+ *
+ * @param context Context to obtain {@link android.content.res.Resources}
+ * @param array The source byte array
+ * @return The drawable created from source byte array
+ */
+ public static Drawable getDrawableFromByteArray(Context context, byte[] array) {
+ if (array == null) {
+ return null;
+ }
+ Bitmap compass = BitmapFactory.decodeByteArray(array, 0, array.length);
+ return new BitmapDrawable(context.getResources(), compass);
+ }
+
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java
index 24c76243d9..1c0e439afc 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/ColorUtils.java
@@ -5,6 +5,7 @@ import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
+import android.os.Build;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.v4.graphics.drawable.DrawableCompat;
@@ -23,49 +24,64 @@ import java.util.regex.Pattern;
public class ColorUtils {
/**
- * Returns a color integer associated as primary color from a theme based on a {@link Context}.
+ * Returns a color integer associated as primary color from a theme based on a Context.
*
* @param context The context used to style the color attributes.
* @return The primary color value of current theme in the form 0xAARRGGBB.
*/
@ColorInt
public static int getPrimaryColor(@NonNull Context context) {
- TypedValue typedValue = new TypedValue();
- Resources.Theme theme = context.getTheme();
- theme.resolveAttribute(R.attr.colorPrimary, typedValue, true);
- return typedValue.data;
+ try {
+ TypedValue typedValue = new TypedValue();
+ Resources.Theme theme = context.getTheme();
+ int id = context.getResources().getIdentifier("colorPrimary", "attrs", context.getPackageName());
+ theme.resolveAttribute(id, typedValue, true);
+ return typedValue.data;
+ } catch (Exception exception) {
+ return getColorCompat(context, R.color.mapbox_blue);
+ }
}
/**
- * Returns a color integer associated as primary dark color from a theme based on a {@link Context}.
+ * Returns a color integer associated as primary dark color from a theme based on a Context.
*
* @param context The context used to style the color attributes.
* @return The primary dark color value of current theme in the form 0xAARRGGBB.
*/
@ColorInt
public static int getPrimaryDarkColor(@NonNull Context context) {
- TypedValue typedValue = new TypedValue();
- Resources.Theme theme = context.getTheme();
- theme.resolveAttribute(R.attr.colorPrimaryDark, typedValue, true);
- return typedValue.data;
+ try {
+ TypedValue typedValue = new TypedValue();
+ Resources.Theme theme = context.getTheme();
+ int id = context.getResources().getIdentifier("colorPrimaryDark", "attrs", context.getPackageName());
+ theme.resolveAttribute(id, typedValue, true);
+ return typedValue.data;
+ } catch (Exception exception) {
+ return getColorCompat(context, R.color.mapbox_blue);
+ }
}
/**
- * Returns a color integer associated as accent color from a theme based on a {@link Context}.
+ * Returns a color integer associated as accent color from a theme based on a Context.
*
* @param context The context used to style the color attributes.
* @return The accent color value of current theme in the form 0xAARRGGBB.
*/
@ColorInt
public static int getAccentColor(@NonNull Context context) {
- TypedValue typedValue = new TypedValue();
- Resources.Theme theme = context.getTheme();
- theme.resolveAttribute(R.attr.colorAccent, typedValue, true);
- return typedValue.data;
+ try {
+ TypedValue typedValue = new TypedValue();
+ Resources.Theme theme = context.getTheme();
+ int id = context.getResources().getIdentifier("colorAccent", "attrs", context.getPackageName());
+ theme.resolveAttribute(id, typedValue, true);
+ return typedValue.data;
+ } catch (Exception exception) {
+ return getColorCompat(context, R.color.mapbox_gray);
+ }
}
/**
- * Returns a color state list associated with a theme based on a {@link Context}
+ * Returns a color state list associated with a theme based on a Context.
*
* @param color The color used for tinting.
* @return A ColorStateList object containing the primary color of a theme
@@ -85,7 +101,7 @@ public class ColorUtils {
}
/**
- * Set a color tint list to the {@link Drawable} of an {@link ImageView}.
+ * Set a color tint list to the Drawable of an ImageView.
*
* @param imageView The view to set the default tint list.
* @param tintColor The color to tint.
@@ -122,4 +138,12 @@ public class ColorUtils {
throw new ConversionException("Not a valid rgb/rgba value");
}
}
+
+ private static int getColorCompat(Context context, int id) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ return context.getResources().getColor(id, context.getTheme());
+ } else {
+ return context.getResources().getColor(id);
+ }
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/Compare.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/Compare.java
new file mode 100644
index 0000000000..c7d7a13a3d
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/Compare.java
@@ -0,0 +1,27 @@
+package com.mapbox.mapboxsdk.utils;
+
+/**
+ * Comparisons from std sdk, which aren't available in API level <= 15
+ */
+public class Compare {
+
+ /**
+ * @see Integer#compare(int, int)
+ * @param x left side
+ * @param y right side
+ * @return std compare value
+ */
+ public static int compare(int x, int y) {
+ return (x < y) ? -1 : ((x == y) ? 0 : 1);
+ }
+
+ /**
+ * @see Boolean#compare(boolean, boolean)
+ * @param x left side
+ * @param y right side
+ * @return std compare value
+ */
+ public static int compare(boolean x, boolean y) {
+ return (x == y) ? 0 : (x ? 1 : -1);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MapFragmentUtils.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MapFragmentUtils.java
index f810d6231d..007880acd1 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MapFragmentUtils.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/utils/MapFragmentUtils.java
@@ -18,12 +18,25 @@ import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
*/
public class MapFragmentUtils {
+ /**
+ * Convert MapboxMapOptions to a bundle of fragment arguments.
+ *
+ * @param options The MapboxMapOptions to convert
+ * @return a bundle of converted fragment arguments
+ */
public static Bundle createFragmentArgs(MapboxMapOptions options) {
Bundle bundle = new Bundle();
bundle.putParcelable(MapboxConstants.FRAG_ARG_MAPBOXMAPOPTIONS, options);
return bundle;
}
+ /**
+ * Convert a bundle of fragment arguments to MapboxMapOptions.
+ *
+ * @param context The context of the activity hosting the fragment
+ * @param args The fragment arguments
+ * @return converted MapboxMapOptions
+ */
public static MapboxMapOptions resolveArgs(Context context, Bundle args) {
MapboxMapOptions options;
if (args != null && args.containsKey(MapboxConstants.FRAG_ARG_MAPBOXMAPOPTIONS)) {
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml b/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml
index 7294f43c02..412d8c5d9b 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml
@@ -11,6 +11,7 @@
<!--Configuration-->
<public name="mapbox_styleUrl" type="attr" />
<public name="mapbox_apiBaseUrl" type="attr" />
+ <public name="mapbox_localIdeographFontFamily" type="attr" />
<!--Camera-->
<public name="mapbox_cameraTargetLng" type="attr" />
@@ -20,7 +21,7 @@
<public name="mapbox_cameraTilt" type="attr" />
<!--Zoom-->
- <public name="mapbox_cameraZoomMax" ftype="attr" />
+ <public name="mapbox_cameraZoomMax" type="attr" />
<public name="mapbox_cameraZoomMin" type="attr" />
<!--Gestures-->
@@ -72,19 +73,24 @@
<public name="mapbox_uiAttributionMarginRight" type="attr" />
<public name="mapbox_uiAttributionMarginBottom" type="attr" />
- <!-- Deprecated to use TextureView-->
+ <!-- Use TextureView-->
<public name="mapbox_renderTextureMode" type="attr" />
+ <public name="mapbox_enableTilePrefetch" type="attr" />
+ <public name="mapbox_enableZMediaOverlay" type="attr" />
+
<!-- Exposed content descriptions -->
<public name="mapbox_logoContentDescription" type="string" />
<!-- Exposed styles -->
<public name="mapbox_style_mapbox_streets" type="string" />
- <public name="mapbox_style_emerald" type="string" />
+ <public name="mapbox_style_outdoors" type="string" />
<public name="mapbox_style_light" type="string" />
<public name="mapbox_style_dark" type="string" />
<public name="mapbox_style_satellite" type="string" />
<public name="mapbox_style_satellite_streets" type="string" />
+ <public name="mapbox_style_traffic_day" type="string" />
+ <public name="mapbox_style_traffic_night" type="string" />
<!-- Exposed strings -->
<public name="mapbox_compassContentDescription" type="string" />
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/color/mapbox_material_bg_selector.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/color/mapbox_material_bg_selector.xml
deleted file mode 100644
index 4c733ed112..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/color/mapbox_material_bg_selector.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:color="?attr/colorPrimaryDark" android:state_pressed="true" />
- <item android:color="?attr/colorPrimary" />
-</selector>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-v21/mapbox_default_bg_selector.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-v21/mapbox_default_bg_selector.xml
deleted file mode 100644
index 2fd6815c23..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-v21/mapbox_default_bg_selector.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="?android:colorControlHighlight">
- <item android:id="@android:id/mask">
- <shape android:shape="oval">
- <solid android:color="@android:color/white" />
- </shape>
- </item>
-</ripple>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/mapbox_mapview_preview.jpg b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/mapbox_mapview_preview.jpg
deleted file mode 100644
index 3a21fc08bc..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/mapbox_mapview_preview.jpg
+++ /dev/null
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/mapbox_infowindow_icon_bg.9.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/mapbox_infowindow_icon_bg.9.png
deleted file mode 100644
index 584b320299..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/mapbox_infowindow_icon_bg.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_default_bg_selector.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_default_bg_selector.xml
deleted file mode 100644
index 3efe48615b..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable/mapbox_default_bg_selector.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@color/mapbox_gray_light" android:state_pressed="true" />
- <item android:drawable="@color/mapbox_gray_light" android:state_focused="true" />
- <item android:drawable="@android:color/transparent" />
-</selector>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_attribution_list_item.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_attribution_list_item.xml
index 763bb118e0..f275860d59 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_attribution_list_item.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_attribution_list_item.xml
@@ -9,5 +9,6 @@
android:paddingLeft="24dp"
android:paddingRight="24dp"
android:textAllCaps="true"
+ android:textIsSelectable="false"
android:textAppearance="?android:attr/textAppearanceButton"
android:textColor="@color/mapbox_blue"/>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_infowindow_content.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_infowindow_content.xml
index 26c974dc0d..3a35396257 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_infowindow_content.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_infowindow_content.xml
@@ -23,6 +23,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="2dp"
+ android:textIsSelectable="false"
android:maxEms="17"
android:textColor="@android:color/black"
android:textSize="18sp"
@@ -34,13 +35,13 @@
android:layout_height="wrap_content"
android:layout_marginBottom="2dp"
android:layout_marginTop="2dp"
+ android:textIsSelectable="false"
android:lineSpacingExtra="1dp"
android:maxEms="17"
android:textColor="@color/mapbox_gray"
android:textSize="14sp"/>
<TextView
- android:id="@+id/infowindow_subdescription"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxEms="17"
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_internal.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_internal.xml
index 6d07de7baa..df7ccaaca9 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_internal.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_internal.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
- <SurfaceView
+ <android.opengl.GLSurfaceView
android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -28,6 +28,7 @@
android:contentDescription="@string/mapbox_compassContentDescription"/>
<ImageView
+ android:visibility="gone"
android:id="@+id/logoView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -35,6 +36,7 @@
android:src="@drawable/mapbox_logo_icon"/>
<ImageView
+ android:visibility="gone"
android:id="@+id/attributionView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_preview.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_preview.xml
deleted file mode 100644
index 1c1ab0e71b..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_mapview_preview.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <ImageView
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:scaleType="centerCrop"
- android:contentDescription="@null"
- android:src="@drawable/mapbox_mapview_preview"
- android:layout_alignParentTop="true"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true"/>
-
- <ImageView
- android:id="@id/logoView"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_alignParentLeft="true"
- android:layout_alignParentStart="true"
- android:layout_marginBottom="@dimen/mapbox_four_dp"
- android:layout_marginLeft="@dimen/mapbox_four_dp"
- android:layout_marginStart="@dimen/mapbox_four_dp"
- android:contentDescription="@null"
- android:src="@drawable/mapbox_logo_icon"/>
-
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_toEndOf="@+id/logoView"
- android:contentDescription="@null"
- android:layout_marginBottom="@dimen/mapbox_four_dp"
- android:background="@drawable/mapbox_default_bg_selector"
- android:src="@drawable/mapbox_info_bg_selector"
- android:layout_marginLeft="@dimen/mapbox_four_dp"
- android:layout_marginStart="@dimen/mapbox_four_dp"
- android:layout_toRightOf="@+id/logoView"/>
-
- <ImageView
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:layout_alignParentEnd="true"
- android:layout_alignParentRight="true"
- android:layout_margin="10dp"
- android:contentDescription="@null"
- android:src="@drawable/mapbox_compass_icon"/>
-
-</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_view_image_marker.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_view_image_marker.xml
index 7e4a079063..51eb46e1d5 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_view_image_marker.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapbox_view_image_marker.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/image"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content" />
+ android:id="@+id/image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@null"/>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values-bg/strings.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values-bg/strings.xml
new file mode 100644
index 0000000000..262e94f368
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values-bg/strings.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="mapbox_compassContentDescription">Компас на картата. Активирай, за да насочиш картата на север.</string>
+ <string name="mapbox_attributionsIconContentDescription">Иконка функции. Активирай, за да покажеш диалог функции.</string>
+ <string name="mapbox_myLocationViewContentDescription">Изглед локация. Това показва местоположението ти на картата.</string>
+ <string name="mapbox_mapActionDescription">Показва карта създадена с Mapbox. Скролни с два пръста. Мащабирай с два пръста.</string>
+ <string name="mapbox_attributionsDialogTitle">Mapbox Android SDK</string>
+ <string name="mapbox_attributionTelemetryTitle">Направи Mapbox картите по-добри.</string>
+ <string name="mapbox_attributionTelemetryMessage">Помагаш OpenStreetMap и Mapbox картите да станат по-добри, като предоставяш анонимни данни за потребление.</string>
+ <string name="mapbox_attributionTelemetryPositive">Съгласявам се</string>
+ <string name="mapbox_attributionTelemetryNegative">Не се съгласявам</string>
+ <string name="mapbox_attributionTelemetryNeutral">Повече инфо</string>
+ <string name="mapbox_offline_error_region_definition_invalid">Предоставените OfflineRegionDefinition не пасват в границите на света: %s</string>
+
+ </resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values-ca/strings.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values-ca/strings.xml
index 34e9914e46..6ed788d1dc 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values-ca/strings.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values-ca/strings.xml
@@ -1,14 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="mapbox_compassContentDescription">Brúixola del mapa. Activa per restablir la rotació del mapa al Nord.</string>
- <string name="mapbox_attributionsIconContentDescription">Icona d\'atribució. Activa per mostrar el diàleg de l\'atribució.</string>
+ <string name="mapbox_attributionsIconContentDescription">Icona d’atribució. Activa per mostrar el diàleg de l’atribució.</string>
<string name="mapbox_myLocationViewContentDescription">Vista de posició. Mostra la teva posició al mapa.</string>
- <string name="mapbox_mapActionDescription">Mostrant un mapa creat amb Mapbox. Desplaça\'t arrossegant amb dos dits. Fes zoom pessigant amb dos dits.</string>
+ <string name="mapbox_mapActionDescription">Mostrant un mapa creat amb Mapbox. Desplaça’t arrossegant amb dos dits. Fes zoom pessigant amb dos dits.</string>
<string name="mapbox_attributionsDialogTitle">Mapbox Android SDK</string>
<string name="mapbox_attributionTelemetryTitle">Millora els mapes de Mapbox</string>
- <string name="mapbox_attributionTelemetryMessage">Estàs ajudant a millorar els mapes d\'OpenStreetMap i de Mapbox aportant dades d\'ús anònimes.</string>
- <string name="mapbox_attributionTelemetryPositive">D\'acord</string>
+ <string name="mapbox_attributionTelemetryMessage">Estàs ajudant a millorar els mapes d’OpenStreetMap i de Mapbox aportant dades d’ús anònimes.</string>
+ <string name="mapbox_attributionTelemetryPositive">D’acord</string>
<string name="mapbox_attributionTelemetryNegative">Disconforme</string>
<string name="mapbox_attributionTelemetryNeutral">Més informació</string>
<string name="mapbox_offline_error_region_definition_invalid">La OfflineRegionDefinition proporcionada no encaixa amb els límits del món: %s</string>
-</resources>
+
+ </resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values-es/strings.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values-es/strings.xml
index 92c055223f..9844642381 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values-es/strings.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values-es/strings.xml
@@ -4,12 +4,13 @@
<string name="mapbox_attributionsIconContentDescription">Ícono de atribución. Actívalo para mostrar el diálogo de atribución.</string>
<string name="mapbox_myLocationViewContentDescription">Vista de ubicación. Muestra tu ubicación en el mapa.</string>
<string name="mapbox_mapActionDescription">Se está mostrando un mapa creado con Mapbox. Arrastra dos dedos para desplazarte o pellizca para acercar.</string>
- <string name="mapbox_attributionsDialogTitle">Mapbox Android SDK</string>
+ <string name="mapbox_attributionsDialogTitle">Mapbox Maps SDK para Android</string>
<string name="mapbox_attributionTelemetryTitle">Ayúdanos a mejorar los mapas de Mapbox</string>
<string name="mapbox_attributionTelemetryMessage">Gracias a tu contribución de datos anónimos de uso, ayudas a mejorar OpenStreetMap y Mapbox.</string>
<string name="mapbox_attributionTelemetryPositive">Aceptar</string>
<string name="mapbox_attributionTelemetryNegative">Rechazar</string>
<string name="mapbox_attributionTelemetryNeutral">Más información</string>
+ <string name="mapbox_attributionErrorNoBrowser">No puede abrir la página Web porque no hay un navegador Web en el dispositivo.</string>
<string name="mapbox_offline_error_region_definition_invalid">El parámetro OfflineRegionDefinition que se ingresó no coincide con los límites mundiales: %s</string>
-
+ <string name="mapbox_telemetrySettings">Ajustes de telemetría</string>
</resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values-fr/strings.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values-fr/strings.xml
new file mode 100644
index 0000000000..48d90c3324
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values-fr/strings.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="mapbox_compassContentDescription">Boussole. Activer pour rétablir l\'orientation de la carte vers le nord.</string>
+ <string name="mapbox_attributionsIconContentDescription">Icone d\'attribution. Activer pour montrer le dialogue d\'attribution.</string>
+ <string name="mapbox_myLocationViewContentDescription">Vue de géolocalisation. Ceci affiche votre localisation sur la carte.</string>
+ <string name="mapbox_mapActionDescription">Affichage d\'une carte créée avec Mapbox. Faites la glisser en traînant deux doigts. Zoomez ou dézoomez en écartant ou rapprochant deux doigts.</string>
+ <string name="mapbox_attributionsDialogTitle">SDK Mapbox pour Android</string>
+ <string name="mapbox_attributionTelemetryTitle">Faire de meilleures cartes Mapbox</string>
+ <string name="mapbox_attributionTelemetryMessage">Vous aidez à améliorer les cartes OpenStreetMap et Mapbox en contribuant des données d\'utilisation anonymes.</string>
+ <string name="mapbox_attributionTelemetryPositive">D\'accord</string>
+ <string name="mapbox_attributionTelemetryNegative">Pas d\'accord</string>
+ <string name="mapbox_attributionTelemetryNeutral">Plus d\'informations</string>
+ <string name="mapbox_offline_error_region_definition_invalid">Le cadre OfflineRegionDefinition pour définir la région de navigation ne tient pas dans les limites du monde : %s</string>
+
+ </resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values-hu/strings.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values-hu/strings.xml
new file mode 100644
index 0000000000..520edb2733
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values-hu/strings.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="mapbox_myLocationViewContentDescription">Hely nézet. Megmutatja, hol vagy a térképen.</string>
+ <string name="mapbox_mapActionDescription">Egy Mapbox-szal készült térkép megjelenítése. Húzd két ujjadat a görgetéshez. Csippentsd össze a nagyításhoz.</string>
+ <string name="mapbox_attributionsDialogTitle">Mapbox Android SDK</string>
+ <string name="mapbox_attributionTelemetryTitle">Tedd jobbá a Mapbox térképeket</string>
+ <string name="mapbox_attributionTelemetryMessage">Segítesz az OpenStreetMap és Mapbox térképek jobbá tételében névtelen felhasználási adatok elküldésével.</string>
+ <string name="mapbox_attributionTelemetryPositive">Egyetértek</string>
+ <string name="mapbox_attributionTelemetryNegative">Nem értek egyet</string>
+ <string name="mapbox_attributionTelemetryNeutral">Több infó</string>
+ <string name="mapbox_offline_error_region_definition_invalid">A megadott OfflineRegionDefinition nem fér bele a világ kereteibe: %s</string>
+
+ </resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values-nl/strings.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values-nl/strings.xml
index fef652c542..f1fcf837ea 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values-nl/strings.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values-nl/strings.xml
@@ -11,4 +11,5 @@
<string name="mapbox_attributionTelemetryNegative">Intrekken</string>
<string name="mapbox_attributionTelemetryNeutral">Meer informatie</string>
<string name="mapbox_offline_error_region_definition_invalid">Aangeleverde OfflineRegionDefinition past niet in de wereld omtrek: %s</string>
-</resources>
+
+ </resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values-ru/strings.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values-ru/strings.xml
new file mode 100644
index 0000000000..39880d56ba
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values-ru/strings.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="mapbox_compassContentDescription">Компас. Активируйте, чтобы повернуть карту на Север.</string>
+ <string name="mapbox_attributionsIconContentDescription">Иконка атрибутов. Активируйте, чтобы показать диалог.</string>
+ <string name="mapbox_myLocationViewContentDescription">Местоположение. Отображает ваше местоположение на карте.</string>
+ <string name="mapbox_mapActionDescription">Отображает карту, созданную при помощи Mapbox. Протисните при помощи двух пальцев. Приблизьте, соединением пальцев. </string>
+ <string name="mapbox_attributionsDialogTitle">Mapbox Android SDK</string>
+ <string name="mapbox_attributionTelemetryTitle">Сделать карты Mapbox лучше</string>
+ <string name="mapbox_attributionTelemetryMessage">Вы помогаете сделать карты OpenStreetMap и Mapbox лучше путем предоставления анонимных данных об использовании.</string>
+ <string name="mapbox_attributionTelemetryPositive">Согласен</string>
+ <string name="mapbox_attributionTelemetryNegative">Не согласен</string>
+ <string name="mapbox_attributionTelemetryNeutral">Дополнительная информация</string>
+ <string name="mapbox_offline_error_region_definition_invalid">Запрошенный OfflineRegionDefinition не входит в допустимые границы: %s</string>
+
+ </resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values-uk/strings.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values-uk/strings.xml
new file mode 100644
index 0000000000..64c7e3efcc
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values-uk/strings.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="mapbox_compassContentDescription">Компас. Натисніть щоб зорієнтувати мапу на північ.</string>
+ <string name="mapbox_attributionsIconContentDescription">Значок атрибуції. Натисніть, щоб показати діалог атрибуції.</string>
+ <string name="mapbox_myLocationViewContentDescription">Визначення положення. Показує ваше місцеположення на мапі.</string>
+ <string name="mapbox_mapActionDescription">Показує мапи створені за допомоги Mapbox. Пересувайте мапу двома пальцями. Змінюйте масштаб стуляючи/розводячи два пальці.</string>
+ <string name="mapbox_attributionsDialogTitle">Mapbox Android SDK</string>
+ <string name="mapbox_attributionTelemetryTitle">Допоможіть зробити мапи Mapbox краще</string>
+ <string name="mapbox_attributionTelemetryMessage">Ви допомагаєте робити мапи OpenStreetMap та Mapbox краще пощирюючи анонімні дані про користування мапами.</string>
+ <string name="mapbox_attributionTelemetryPositive">Погоджуюсь</string>
+ <string name="mapbox_attributionTelemetryNegative">Не погоджуюсь</string>
+ <string name="mapbox_attributionTelemetryNeutral">Додаткова інформація</string>
+ <string name="mapbox_offline_error_region_definition_invalid">Межі ділянки для оффлайнового користування даними за межами світу: %s</string>
+
+ </resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values-vi/strings.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values-vi/strings.xml
index a0cad6487a..77e72a4db7 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values-vi/strings.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values-vi/strings.xml
@@ -4,12 +4,13 @@
<string name="mapbox_attributionsIconContentDescription">Biểu tượng ghi công. Kích hoạt để xem hộp thoại ghi công.</string>
<string name="mapbox_myLocationViewContentDescription">Cái chỉ vị trí. Cái này chỉ vị trí của bạn trên bản đồ.</string>
<string name="mapbox_mapActionDescription">Đang xem bản đồ được xây dựng dùng Mapbox. Kéo hai ngón tay để cuộn. Chụm các ngón tay lại để phóng to. Tách các ngón tay ra để thu nhỏ.</string>
- <string name="mapbox_attributionsDialogTitle">Mapbox Android SDK</string>
+ <string name="mapbox_attributionsDialogTitle">Mapbox Maps SDK cho Android</string>
<string name="mapbox_attributionTelemetryTitle">Cải tiến các Bản đồ Mapbox</string>
<string name="mapbox_attributionTelemetryMessage">Bạn đang giúp cải tiến các bản đồ OpenStreetMap và Mapbox bằng cách đóng góp dữ liệu vô danh hóa về cách sử dụng.</string>
<string name="mapbox_attributionTelemetryPositive">Đồng ý</string>
<string name="mapbox_attributionTelemetryNegative">Phản đối</string>
<string name="mapbox_attributionTelemetryNeutral">Thông tin thêm</string>
+ <string name="mapbox_attributionErrorNoBrowser">Không thể mở trang Web vì thiết bị thiếu trình duyệt.</string>
<string name="mapbox_offline_error_region_definition_invalid">OfflineRegionDefinition được cung cấp không vừa thế giới: %s</string>
-
+ <string name="mapbox_telemetrySettings">Thiết lập Trình viễn trắc</string>
</resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml
index e17f01d075..97adce8a4e 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml
@@ -5,6 +5,7 @@
<!--Configuration-->
<attr name="mapbox_styleUrl" format="string"/>
<attr name="mapbox_apiBaseUrl" format="string"/>
+ <attr name="mapbox_localIdeographFontFamily" format="string"/>
<!--Camera-->
<attr name="mapbox_cameraTargetLat" format="float"/>
@@ -40,6 +41,7 @@
<attr name="mapbox_myLocationBackgroundMarginBottom" format="dimension"/>
<attr name="mapbox_myLocationAccuracyTintColor" format="color"/>
<attr name="mapbox_myLocationAccuracyAlpha" format="integer"/>
+ <attr name="mapbox_myLocationAccuracyThreshold" format="float"/>
<!--Compass-->
<attr name="mapbox_uiCompass" format="boolean"/>
@@ -113,9 +115,12 @@
<attr name="mapbox_uiAttributionMarginBottom" format="dimension"/>
<attr name="mapbox_uiAttributionTintColor" format="color"/>
- <!-- Deprecated to use TextureView-->
+ <!-- Use TextureView-->
<attr name="mapbox_renderTextureMode" format="boolean"/>
+ <attr name="mapbox_enableTilePrefetch" format="boolean"/>
+ <attr name="mapbox_enableZMediaOverlay" format="boolean"/>
+
</declare-styleable>
<declare-styleable name="mapbox_BubbleLayout">
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/colors.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/colors.xml
index 63ef42c2c3..b51c890e5c 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/colors.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/colors.xml
@@ -1,7 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="mapbox_gray">#7D7F80</color>
- <color name="mapbox_gray_light">#EEEEEE</color>
<color name="mapbox_blue">#1E8CAB</color>
- <color name="mapbox_my_location_ring">@color/mapbox_blue</color>
</resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml
index 8edbd47c29..1c6a265587 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/dimens.xml
@@ -2,17 +2,8 @@
<resources>
<dimen name="mapbox_infowindow_tipview_width">8dp</dimen>
<dimen name="mapbox_infowindow_margin">8dp</dimen>
- <dimen name="mapbox_infowindow_offset">-2dp</dimen>
- <dimen name="mapbox_infowindow_line_width">1.5dp</dimen>
- <dimen name="mapbox_attribution_icon_left_padding">@dimen/mapbox_two_dp</dimen>
- <dimen name="mapbox_attribution_icon_top_padding">@dimen/mapbox_two_dp</dimen>
- <dimen name="mapbox_attribution_icon_right_padding">@dimen/mapbox_two_dp</dimen>
- <dimen name="mapbox_attribution_icon_bottom_padding">@dimen/mapbox_two_dp</dimen>
- <dimen name="mapbox_two_dp">2dp</dimen>
<dimen name="mapbox_four_dp">4dp</dimen>
<dimen name="mapbox_eight_dp">8dp</dimen>
- <dimen name="mapbox_ten_dp">10dp</dimen>
- <dimen name="mapbox_sixteen_dp">16dp</dimen>
<dimen name="mapbox_ninety_two_dp">92dp</dimen>
<dimen name="mapbox_my_locationview_outer_circle">18dp</dimen>
</resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/strings.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/strings.xml
index 65fb3e14a3..79c2c8d699 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/strings.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/strings.xml
@@ -4,7 +4,7 @@
<string name="mapbox_attributionsIconContentDescription">Attribution icon. Activate to show attribution dialog.</string>
<string name="mapbox_myLocationViewContentDescription">Location View. This shows your location on the map.</string>
<string name="mapbox_mapActionDescription">Showing a Map created with Mapbox. Scroll by dragging two fingers. Zoom by pinching two fingers.</string>
- <string name="mapbox_attributionsDialogTitle">Mapbox Android SDK</string>
+ <string name="mapbox_attributionsDialogTitle">Mapbox Maps SDK for Android</string>
<string name="mapbox_attributionTelemetryTitle">Make Mapbox Maps Better</string>
<string name="mapbox_attributionTelemetryMessage">You are helping to make OpenStreetMap and Mapbox maps better by contributing anonymous usage data.</string>
<string name="mapbox_attributionTelemetryPositive">Agree</string>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/styles.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/styles.xml
deleted file mode 100644
index eba1fb3a7d..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/styles.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-
- <style name="mapbox_AlertDialogStyle" parent="Theme.AppCompat.Light.Dialog.Alert"/>
-
-</resources>
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/resources/fabric/com.mapbox.mapboxsdk.mapbox-android-sdk.properties b/platform/android/MapboxGLAndroidSDK/src/main/resources/fabric/com.mapbox.mapboxsdk.mapbox-android-sdk.properties
index bc0350fe1f..716f0ffe70 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/resources/fabric/com.mapbox.mapboxsdk.mapbox-android-sdk.properties
+++ b/platform/android/MapboxGLAndroidSDK/src/main/resources/fabric/com.mapbox.mapboxsdk.mapbox-android-sdk.properties
@@ -1,3 +1,3 @@
fabric-identifier=com.mapbox.mapboxsdk.mapbox-android-sdk
-fabric-version=5.0.1
+fabric-version=5.1.4
fabric-build-type=binary
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java
index 6ee5c157b9..7a28d846ea 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java
@@ -5,6 +5,7 @@ import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import com.mapbox.mapboxsdk.exceptions.MapboxConfigurationException;
+import com.mapbox.services.android.telemetry.location.LocationEngine;
import org.junit.Before;
import org.junit.Test;
@@ -24,11 +25,13 @@ public class MapboxTest {
private Context context;
private Context appContext;
+ private LocationEngine locationSource;
@Before
public void before() {
context = mock(Context.class);
appContext = mock(Context.class);
+ locationSource = mock(LocationEngine.class);
when(context.getApplicationContext()).thenReturn(appContext);
}
@@ -80,7 +83,7 @@ public class MapboxTest {
}
private void injectMapboxSingleton(String accessToken) {
- Mapbox mapbox = new Mapbox(appContext, accessToken);
+ Mapbox mapbox = new Mapbox(appContext, accessToken, locationSource);
try {
Field field = Mapbox.class.getDeclaredField("INSTANCE");
field.setAccessible(true);
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java
index 8d9a360714..c3d13f0c66 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java
@@ -2,6 +2,7 @@ package com.mapbox.mapboxsdk.geometry;
import android.os.Parcelable;
+import com.mapbox.mapboxsdk.constants.GeometryConstants;
import com.mapbox.mapboxsdk.exceptions.InvalidLatLngBoundsException;
import com.mapbox.mapboxsdk.utils.MockParcel;
@@ -74,15 +75,6 @@ public class LatLngBoundsTest {
}
@Test
- public void emptySpan() {
- latLngBounds = new LatLngBounds.Builder()
- .include(LAT_LNG_NOT_NULL_ISLAND)
- .include(LAT_LNG_NOT_NULL_ISLAND)
- .build();
- assertTrue("Should be empty", latLngBounds.isEmptySpan());
- }
-
- @Test
public void notEmptySpan() {
latLngBounds = new LatLngBounds.Builder()
.include(LAT_LNG_NOT_NULL_ISLAND)
@@ -281,4 +273,20 @@ public class LatLngBoundsTest {
Parcelable parcel = MockParcel.obtain(latLngBounds);
assertEquals("Parcel should match original object", parcel, latLngBounds);
}
+
+ @Test
+ public void fromTileID() {
+ LatLngBounds bounds = LatLngBounds.from(0, 0, 0);
+ assertEquals(GeometryConstants.MIN_LONGITUDE, bounds.getLonWest(), DELTA);
+ assertEquals(GeometryConstants.MIN_MERCATOR_LATITUDE, bounds.getLatSouth(), DELTA);
+ assertEquals(GeometryConstants.MAX_LONGITUDE, bounds.getLonEast(), DELTA);
+ assertEquals(GeometryConstants.MAX_MERCATOR_LATITUDE, bounds.getLatNorth(), DELTA);
+
+ bounds = LatLngBounds.from(10, 288, 385);
+ assertEquals(-78.75, bounds.getLonWest(), DELTA);
+ assertEquals(40.446947059600497, bounds.getLatSouth(), DELTA);
+ assertEquals(-78.3984375, bounds.getLonEast(), DELTA);
+ assertEquals(40.713955826286039, bounds.getLatNorth(), DELTA);
+
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java
index 06e93b9d2f..8e47f069c3 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java
@@ -12,6 +12,7 @@ import org.junit.rules.ExpectedException;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -255,8 +256,17 @@ public class LatLngTest {
@Test
public void testWrapped() {
- LatLng latLng = new LatLng(45.0, -185.0).wrap();
- assertEquals("longitude wrapped value", latLng.getLongitude(), 175.0, DELTA);
+ LatLng originalLatLng = new LatLng(45.0, -185.0);
+ LatLng newLatlng = originalLatLng.wrap();
+ assertNotSame(" new wrapped LatLng is created", originalLatLng, newLatlng);
+ assertEquals("longitude wrapped value", originalLatLng.getLongitude(), -185.0, DELTA);
+ assertEquals("longitude wrapped value", newLatlng.getLongitude(), 175.0, DELTA);
+
+ newLatlng = new LatLng(45.0, 180.0).wrap();
+ assertEquals("longitude wrapped max value", newLatlng.getLongitude(), 180.0, DELTA);
+
+ newLatlng = new LatLng(45.0, -180.0).wrap();
+ assertEquals("longitude wrapped min value", newLatlng.getLongitude(), -180.0, DELTA);
}
@Test
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/AnnotationManagerTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/AnnotationManagerTest.java
index 0d592f9bb3..239ad7392b 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/AnnotationManagerTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/AnnotationManagerTest.java
@@ -10,6 +10,7 @@ import com.mapbox.mapboxsdk.annotations.MarkerViewManager;
import com.mapbox.mapboxsdk.geometry.LatLng;
import org.junit.Test;
+import org.mockito.ArgumentMatchers;
import java.util.ArrayList;
import java.util.List;
@@ -32,8 +33,9 @@ public class AnnotationManagerTest {
Markers markers = new MarkerContainer(aNativeMapView, aMapView, annotationsArray, aIconManager, aMarkerViewManager);
Polygons polygons = new PolygonContainer(aNativeMapView, annotationsArray);
Polylines polylines = new PolylineContainer(aNativeMapView, annotationsArray);
+ ShapeAnnotations shapeAnnotations = new ShapeAnnotationContainer(aNativeMapView, annotationsArray);
AnnotationManager annotationManager = new AnnotationManager(aNativeMapView, aMapView, annotationsArray,
- aMarkerViewManager, aIconManager, annotations, markers, polygons, polylines);
+ aMarkerViewManager, aIconManager, annotations, markers, polygons, polylines, shapeAnnotations);
Marker aMarker = mock(Marker.class);
long aId = 5L;
when(aNativeMapView.addMarker(aMarker)).thenReturn(aId);
@@ -58,18 +60,23 @@ public class AnnotationManagerTest {
Markers markers = new MarkerContainer(aNativeMapView, aMapView, annotationsArray, aIconManager, aMarkerViewManager);
Polygons polygons = new PolygonContainer(aNativeMapView, annotationsArray);
Polylines polylines = new PolylineContainer(aNativeMapView, annotationsArray);
+ ShapeAnnotations shapeAnnotations = new ShapeAnnotationContainer(aNativeMapView, annotationsArray);
AnnotationManager annotationManager = new AnnotationManager(aNativeMapView, aMapView, annotationsArray,
- aMarkerViewManager, aIconManager, annotations, markers, polygons, polylines);
+ aMarkerViewManager, aIconManager, annotations, markers, polygons, polylines, shapeAnnotations);
long firstId = 1L;
long secondId = 2L;
List<BaseMarkerOptions> markerList = new ArrayList<>();
MarkerOptions firstMarkerOption = new MarkerOptions().position(new LatLng()).title("first");
MarkerOptions secondMarkerOption = new MarkerOptions().position(new LatLng()).title("second");
+
markerList.add(firstMarkerOption);
markerList.add(secondMarkerOption);
MapboxMap aMapboxMap = mock(MapboxMap.class);
when(aNativeMapView.addMarker(any(Marker.class))).thenReturn(firstId, secondId);
+ when(aNativeMapView.addMarkers(ArgumentMatchers.<Marker>anyList()))
+ .thenReturn(new long[]{firstId, secondId});
+
annotationManager.addMarkers(markerList, aMapboxMap);
assertEquals(2, annotationManager.getAnnotations().size());
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcherTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcherTest.java
new file mode 100644
index 0000000000..090d274fe7
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/CameraChangeDispatcherTest.java
@@ -0,0 +1,87 @@
+package com.mapbox.mapboxsdk.maps;
+
+import org.junit.Test;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+public class CameraChangeDispatcherTest {
+
+ @Test
+ public void testSetCameraIdleListener() {
+ CameraChangeDispatcher dispatcher = new CameraChangeDispatcher();
+ MapboxMap.OnCameraIdleListener listener = mock(MapboxMap.OnCameraIdleListener.class);
+ dispatcher.setOnCameraIdleListener(listener);
+ dispatcher.onCameraMoveStarted(MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE);
+ dispatcher.onCameraIdle();
+ verify(listener).onCameraIdle();
+ }
+
+ @Test
+ public void testSetCameraMoveStartedListener() {
+ CameraChangeDispatcher dispatcher = new CameraChangeDispatcher();
+ MapboxMap.OnCameraMoveStartedListener listener = mock(MapboxMap.OnCameraMoveStartedListener.class);
+ dispatcher.setOnCameraMoveStartedListener(listener);
+ dispatcher.onCameraMoveStarted(MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE);
+ verify(listener).onCameraMoveStarted(MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE);
+ }
+
+ @Test
+ public void testSetCameraMoveCancelListener() {
+ CameraChangeDispatcher dispatcher = new CameraChangeDispatcher();
+ MapboxMap.OnCameraMoveCanceledListener listener = mock(MapboxMap.OnCameraMoveCanceledListener.class);
+ dispatcher.setOnCameraMoveCanceledListener(listener);
+ dispatcher.onCameraMoveStarted(MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE);
+ dispatcher.onCameraMoveCanceled();
+ verify(listener).onCameraMoveCanceled();
+ }
+
+ @Test
+ public void testSetCameraMoveListener() {
+ CameraChangeDispatcher dispatcher = new CameraChangeDispatcher();
+ MapboxMap.OnCameraMoveListener listener = mock(MapboxMap.OnCameraMoveListener.class);
+ dispatcher.setOnCameraMoveListener(listener);
+ dispatcher.onCameraMoveStarted(MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE);
+ dispatcher.onCameraMove();
+ verify(listener).onCameraMove();
+ }
+
+ @Test
+ public void testAddCameraIdleListener() {
+ CameraChangeDispatcher dispatcher = new CameraChangeDispatcher();
+ MapboxMap.OnCameraIdleListener listener = mock(MapboxMap.OnCameraIdleListener.class);
+ dispatcher.addOnCameraIdleListener(listener);
+ dispatcher.onCameraMoveStarted(MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE);
+ dispatcher.onCameraIdle();
+ verify(listener).onCameraIdle();
+ }
+
+ @Test
+ public void testAddCameraMoveStartedListener() {
+ CameraChangeDispatcher dispatcher = new CameraChangeDispatcher();
+ MapboxMap.OnCameraMoveStartedListener listener = mock(MapboxMap.OnCameraMoveStartedListener.class);
+ dispatcher.addOnCameraMoveStartedListener(listener);
+ dispatcher.onCameraMoveStarted(MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE);
+ verify(listener).onCameraMoveStarted(MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE);
+ }
+
+ @Test
+ public void testAddCameraMoveCancelListener() {
+ CameraChangeDispatcher dispatcher = new CameraChangeDispatcher();
+ MapboxMap.OnCameraMoveCanceledListener listener = mock(MapboxMap.OnCameraMoveCanceledListener.class);
+ dispatcher.addOnCameraMoveCancelListener(listener);
+ dispatcher.onCameraMoveStarted(MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE);
+ dispatcher.onCameraMoveCanceled();
+ verify(listener).onCameraMoveCanceled();
+ }
+
+ @Test
+ public void testAddCameraMoveListener() {
+ CameraChangeDispatcher dispatcher = new CameraChangeDispatcher();
+ MapboxMap.OnCameraMoveListener listener = mock(MapboxMap.OnCameraMoveListener.class);
+ dispatcher.addOnCameraMoveListener(listener);
+ dispatcher.onCameraMoveStarted(MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE);
+ dispatcher.onCameraMove();
+ verify(listener).onCameraMove();
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapTouchListenersTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapTouchListenersTest.java
new file mode 100644
index 0000000000..eeb00355bd
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapTouchListenersTest.java
@@ -0,0 +1,95 @@
+package com.mapbox.mapboxsdk.maps;
+
+import android.graphics.PointF;
+
+import com.mapbox.mapboxsdk.geometry.LatLng;
+
+import org.junit.Test;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class MapTouchListenersTest {
+
+ @Test
+ public void onMapClickListenerTest() throws Exception {
+ LatLng latLng = new LatLng();
+ PointF pointF = new PointF();
+
+ Projection projection = mock(Projection.class);
+ when(projection.fromScreenLocation(pointF)).thenReturn(latLng);
+ MapGestureDetector mapGestureDetector = new MapGestureDetector(null,
+ null, projection, null, null, null, null);
+
+ MapboxMap.OnMapClickListener listener = mock(MapboxMap.OnMapClickListener.class);
+ mapGestureDetector.addOnMapClickListener(listener);
+ mapGestureDetector.notifyOnMapClickListeners(pointF);
+ verify(listener, times(1)).onMapClick(latLng);
+
+ mapGestureDetector.removeOnMapClickListener(listener);
+ mapGestureDetector.notifyOnMapClickListeners(pointF);
+ verify(listener, times(1)).onMapClick(latLng);
+ }
+
+ @Test
+ public void onMapLongClickListenerTest() throws Exception {
+ LatLng latLng = new LatLng();
+ PointF pointF = new PointF();
+
+ Projection projection = mock(Projection.class);
+ when(projection.fromScreenLocation(pointF)).thenReturn(latLng);
+ MapGestureDetector mapGestureDetector = new MapGestureDetector(null,
+ null, projection, null, null, null, null);
+
+ MapboxMap.OnMapLongClickListener listener = mock(MapboxMap.OnMapLongClickListener.class);
+ mapGestureDetector.addOnMapLongClickListener(listener);
+ mapGestureDetector.notifyOnMapLongClickListeners(pointF);
+ verify(listener, times(1)).onMapLongClick(latLng);
+
+ mapGestureDetector.removeOnMapLongClickListener(listener);
+ mapGestureDetector.notifyOnMapLongClickListeners(pointF);
+ verify(listener, times(1)).onMapLongClick(latLng);
+ }
+
+ @Test
+ public void onFlingListenerTest() throws Exception {
+ LatLng latLng = new LatLng();
+ PointF pointF = new PointF();
+
+ Projection projection = mock(Projection.class);
+ when(projection.fromScreenLocation(pointF)).thenReturn(latLng);
+ MapGestureDetector mapGestureDetector = new MapGestureDetector(null,
+ null, projection, null, null, null, null);
+
+ MapboxMap.OnFlingListener listener = mock(MapboxMap.OnFlingListener.class);
+ mapGestureDetector.addOnFlingListener(listener);
+ mapGestureDetector.notifyOnFlingListeners();
+ verify(listener, times(1)).onFling();
+
+ mapGestureDetector.removeOnFlingListener(listener);
+ mapGestureDetector.notifyOnFlingListeners();
+ verify(listener, times(1)).onFling();
+ }
+
+ @Test
+ public void onScrollListenerTest() throws Exception {
+ LatLng latLng = new LatLng();
+ PointF pointF = new PointF();
+
+ Projection projection = mock(Projection.class);
+ when(projection.fromScreenLocation(pointF)).thenReturn(latLng);
+ MapGestureDetector mapGestureDetector = new MapGestureDetector(null,
+ null, projection, null, null, null, null);
+
+ MapboxMap.OnScrollListener listener = mock(MapboxMap.OnScrollListener.class);
+ mapGestureDetector.addOnScrollListener(listener);
+ mapGestureDetector.notifyOnScrollListeners();
+ verify(listener, times(1)).onScroll();
+
+ mapGestureDetector.removeOnScrollListener(listener);
+ mapGestureDetector.notifyOnScrollListeners();
+ verify(listener, times(1)).onScroll();
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java
index ce0cb00b0b..4f929641f3 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java
@@ -186,5 +186,15 @@ public class MapboxMapOptionsTest {
assertEquals(Color.BLUE, new MapboxMapOptions()
.myLocationBackgroundTintColor(Color.BLUE).getMyLocationBackgroundTintColor());
}
+
+ @Test
+ public void testPrefetchesTiles() {
+ // Default value
+ assertTrue(new MapboxMapOptions().getPrefetchesTiles());
+
+ // Check mutations
+ assertTrue(new MapboxMapOptions().setPrefetchesTiles(true).getPrefetchesTiles());
+ assertFalse(new MapboxMapOptions().setPrefetchesTiles(false).getPrefetchesTiles());
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java
new file mode 100644
index 0000000000..5e9f94db28
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapTest.java
@@ -0,0 +1,47 @@
+package com.mapbox.mapboxsdk.maps;
+
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
+import com.mapbox.mapboxsdk.geometry.LatLng;
+import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.mockito.Mockito.mock;
+
+public class MapboxMapTest {
+
+ private MapboxMap mapboxMap;
+
+ @Before
+ public void beforeTest() {
+
+ mapboxMap = new MapboxMap(mock(NativeMapView.class),
+ mock(Transform.class),
+ mock(UiSettings.class),
+ mock(TrackingSettings.class),
+ mock(MyLocationViewSettings.class),
+ mock(Projection.class),
+ mock(MapboxMap.OnRegisterTouchListener.class),
+ mock(AnnotationManager.class),
+ mock(CameraChangeDispatcher.class));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testAnimateCameraChecksDurationPositive() {
+ mapboxMap.animateCamera(CameraUpdateFactory.newLatLng(new LatLng(30.0, 30.0)),
+ 0, null);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testEaseCameraChecksDurationPositive() {
+ mapboxMap.easeCamera(CameraUpdateFactory.newLatLng(new LatLng(30.0, 30.0)),
+ 0, null);
+ }
+
+ @After
+ public void afterTest() {
+ mapboxMap = null;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java
new file mode 100644
index 0000000000..eb1ce8bfaa
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java
@@ -0,0 +1,1010 @@
+package com.mapbox.mapboxsdk.style.expressions;
+
+import android.graphics.Color;
+
+import com.mapbox.mapboxsdk.style.layers.PropertyFactory;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+
+import static com.mapbox.mapboxsdk.style.expressions.Expression.acos;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.all;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.any;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.array;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.asin;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.at;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.atan;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.bool;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.coalesce;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.color;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.concat;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.cos;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.cubicBezier;
+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.e;
+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.geometryType;
+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.heatmapDensity;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.id;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.interpolate;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.length;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.let;
+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.ln;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.ln2;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.log10;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.log2;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.lt;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.lte;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.match;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.max;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.min;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.mod;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.neq;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.not;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.number;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.object;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.pi;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.pow;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.product;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.properties;
+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.sin;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.sqrt;
+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.subtract;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.sum;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.switchCase;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.tan;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.toBool;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.toColor;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.toNumber;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.toRgba;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.typeOf;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.upcase;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.var;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.zoom;
+import static junit.framework.Assert.assertTrue;
+
+/**
+ * Expression unit tests that validate the expression output with the expected Object[]array representation.
+ */
+public class ExpressionTest {
+
+ @Test
+ public void testRgb() throws Exception {
+ Object[] expected = new Object[] {"rgb", 0, 0, 0};
+ Object[] actual = rgb(literal(0), literal(0), literal(0)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testRgbLiteral() throws Exception {
+ Object[] expected = new Object[] {"rgb", 0, 0, 0};
+ Object[] actual = rgb(0, 0, 0).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testRgba() throws Exception {
+ Object[] expected = new Object[] {"rgba", 0, 0, 0, 1};
+ Object[] actual = rgba(literal(0), literal(0), literal(0), literal(1)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testRgbaLiteral() throws Exception {
+ Object[] expected = new Object[] {"rgba", 0, 0, 0, 1};
+ Object[] actual = rgba(0, 0, 0, 1).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testToRgba() throws Exception {
+ Object[] expected = new Object[] {"to-rgba", PropertyFactory.colorToRgbaString(Color.RED)};
+ Object[] actual = toRgba(color(Color.RED)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testEq() throws Exception {
+ Object[] expected = new Object[] {"==", 1, 1};
+ Object[] actual = eq(literal(1), literal(1)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testEqLiteral() throws Exception {
+ Object[] expected = new Object[] {"==", 1, 1};
+ Object[] actual = eq(1, 1).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testNeq() throws Exception {
+ Object[] expected = new Object[] {"!=", 0, 1};
+ Object[] actual = neq(literal(0), literal(1)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testNeqLiteral() throws Exception {
+ Object[] expected = new Object[] {"!=", 0, 1};
+ Object[] actual = neq(0, 1).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testGt() throws Exception {
+ Object[] expected = new Object[] {">", 0, 1};
+ Object[] actual = gt(literal(0), literal(1)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testGtLiteral() throws Exception {
+ Object[] expected = new Object[] {">", 0, 1};
+ Object[] actual = gt(0, 1).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testLt() throws Exception {
+ Object[] expected = new Object[] {"<", 1, 0};
+ Object[] actual = lt(literal(1), literal(0)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testLtLiteral() throws Exception {
+ Object[] expected = new Object[] {"<", 1, 0};
+ Object[] actual = lt(1, 0).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testGte() throws Exception {
+ Object[] expected = new Object[] {">=", 1, 1};
+ Object[] actual = gte(literal(1), literal(1)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testGteLiteral() throws Exception {
+ Object[] expected = new Object[] {">=", 1, 1};
+ Object[] actual = gte(1, 1).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testLte() throws Exception {
+ Object[] expected = new Object[] {"<=", 1, 1};
+ Object[] actual = lte(literal(1), literal(1)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testLteLiteral() throws Exception {
+ Object[] expected = new Object[] {"<=", 1, 1};
+ Object[] actual = lte(1, 1).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testAll() throws Exception {
+ Object[] expected = new Object[] {"all", true, true, true};
+ Object[] actual = all(literal(true), literal(true), literal(true)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testAny() throws Exception {
+ Object[] expected = new Object[] {"any", true, false, false};
+ Object[] actual = any(literal(true), literal(false), literal(false)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testNot() throws Exception {
+ Object[] expected = new Object[] {"!", false};
+ Object[] actual = not(literal(false)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testNotLiteral() throws Exception {
+ Object[] expected = new Object[] {"!", false};
+ Object[] actual = not(false).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testSwitchCase() throws Exception {
+ Object[] expectedCaseOneGet = new Object[] {"get", "key1"};
+ Object[] expectedCaseOne = new Object[] {"==", expectedCaseOneGet, "value1"};
+ Object[] expectedCaseTwoGet = new Object[] {"get", "key2"};
+ Object[] expectedCaseTwo = new Object[] {"!=", expectedCaseTwoGet, "value2"};
+ Object[] expected = new Object[] {"case", expectedCaseOne, expectedCaseTwo};
+
+ Object[] actual = switchCase(
+ eq(get(literal("key1")), literal("value1")),
+ neq(get(literal("key2")), literal("value2"))
+ ).toArray();
+
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testSwitchCaseLiteral() throws Exception {
+ Object[] expectedCaseOneGet = new Object[] {"get", "key1"};
+ Object[] expectedCaseOne = new Object[] {"==", expectedCaseOneGet, "value1"};
+ Object[] expectedCaseTwoGet = new Object[] {"get", "key2"};
+ Object[] expectedCaseTwo = new Object[] {"!=", expectedCaseTwoGet, "value2"};
+ Object[] expected = new Object[] {"case", expectedCaseOne, expectedCaseTwo};
+
+ Object[] actual = switchCase(
+ eq(get("key1"), literal("value1")),
+ neq(get("key2"), literal("value2"))
+ ).toArray();
+
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testMatch() throws Exception {
+ Object[] labelZero = new Object[] {"a", "output"};
+ Object[] labelOne = new Object[] {"b", "output2"};
+ Object[] labelTwo = new Object[] {"c", "output3"};
+
+ Object[] expected = new Object[] {"match", labelZero, labelOne, labelTwo};
+ Object[] actual = match(literal(labelZero), literal(labelOne), literal(labelTwo)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testCoalesce() throws Exception {
+ Object[] expectedGetOne = new Object[] {"get", "invalidKey"};
+ Object[] expectedGetTwo = new Object[] {"get", "validKey"};
+ Object[] expected = new Object[] {"coalesce", expectedGetOne, expectedGetTwo};
+
+ Object[] actual = coalesce(
+ get(literal("invalidKey")),
+ get(literal("validKey"))
+ ).toArray();
+
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testCoalesceLiteral() throws Exception {
+ Object[] expectedGetOne = new Object[] {"get", "invalidKey"};
+ Object[] expectedGetTwo = new Object[] {"get", "validKey"};
+ Object[] expected = new Object[] {"coalesce", expectedGetOne, expectedGetTwo};
+
+ Object[] actual = coalesce(
+ get("invalidKey"),
+ get("validKey")
+ ).toArray();
+
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testProperties() throws Exception {
+ Object[] expected = new Object[] {"properties"};
+ Object[] actual = properties().toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testGeometryType() throws Exception {
+ Object[] expected = new Object[] {"geometry-type"};
+ Object[] actual = geometryType().toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testId() throws Exception {
+ Object[] expected = new Object[] {"id"};
+ Object[] actual = id().toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testHeatmapDensity() throws Exception {
+ Object[] expected = new Object[] {"heatmap-density"};
+ Object[] actual = heatmapDensity().toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testAt() throws Exception {
+ Object[] expected = new Object[] {"at", 3, new Object[] {"one", "two"}};
+ Object[] actual = at(literal(3), literal(new Object[] {"one", "two"})).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testAtLiteral() throws Exception {
+ Object[] expected = new Object[] {"at", 3, new Object[] {"one", "two"}};
+ Object[] actual = at(3, literal(new Object[] {"one", "two"})).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testAtExpression() throws Exception {
+ Object[] expected = new Object[] {"at", 3, new Object[] {"properties"}};
+ Object[] actual = at(literal(3), properties()).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testGet() throws Exception {
+ Object[] expected = new Object[] {"get", "key"};
+ Object[] actual = get(literal("key")).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testGetLiteral() throws Exception {
+ Object[] expected = new Object[] {"get", "key"};
+ Object[] actual = get("key").toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testGetObject() throws Exception {
+ Object[] expected = new Object[] {"get", "key", new Object[] {"properties"}};
+ Object[] actual = get(literal("key"), properties()).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testGetObjectLiteral() throws Exception {
+ Object[] expected = new Object[] {"get", "key", new Object[] {"properties"}};
+ Object[] actual = get("key", properties()).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testHas() throws Exception {
+ Object[] expected = new Object[] {"has", "key"};
+ Object[] actual = has(literal("key")).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testHasLiteral() throws Exception {
+ Object[] expected = new Object[] {"has", "key"};
+ Object[] actual = has("key").toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testHasObject() throws Exception {
+ Object[] expected = new Object[] {"has", "key", new Object[] {"properties"}};
+ Object[] actual = has(literal("key"), properties()).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testHasObjectLiteral() throws Exception {
+ Object[] expected = new Object[] {"has", "key", new Object[] {"properties"}};
+ Object[] actual = has("key", properties()).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testHasExpression() throws Exception {
+ Object[] expected = new Object[] {"has", new Object[] {"get", "key"}, new Object[] {"properties"}};
+ Object[] actual = has(get(literal("key")), properties()).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testHasExpressionLiteral() throws Exception {
+ Object[] expected = new Object[] {"has", new Object[] {"get", "key"}, new Object[] {"properties"}};
+ Object[] actual = has(get("key"), properties()).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testLength() throws Exception {
+ Object[] expected = new Object[] {"length", "key"};
+ Object[] actual = length(literal("key")).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testLengthLiteral() throws Exception {
+ Object[] expected = new Object[] {"length", "key"};
+ Object[] actual = length("key").toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testLengthExpression() throws Exception {
+ Object[] expected = new Object[] {"length", new Object[] {"get", "key"}};
+ Object[] actual = length(get(literal("key"))).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testLn2() throws Exception {
+ Object[] expected = new Object[] {"ln2"};
+ Object[] actual = ln2().toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testPi() throws Exception {
+ Object[] expected = new Object[] {"pi"};
+ Object[] actual = pi().toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testE() throws Exception {
+ Object[] expected = new Object[] {"e"};
+ Object[] actual = e().toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testSum() throws Exception {
+ Object[] expected = new Object[] {"+", 1, 2};
+ Object[] actual = sum(literal(1), literal(2)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testSumLiteral() throws Exception {
+ Object[] expected = new Object[] {"+", 1, 2};
+ Object[] actual = sum(1, 2).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testProduct() throws Exception {
+ Object[] expected = new Object[] {"*", 1, 2};
+ Object[] actual = product(literal(1), literal(2)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testProductLiteral() throws Exception {
+ Object[] expected = new Object[] {"*", 1, 2};
+ Object[] actual = product(1, 2).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testSubtract() throws Exception {
+ Object[] expected = new Object[] {"-", 2, 1};
+ Object[] actual = subtract(literal(2), literal(1)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testSubtractLiteral() throws Exception {
+ Object[] expected = new Object[] {"-", 2, 1};
+ Object[] actual = subtract(2, 1).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testDivision() throws Exception {
+ Object[] expected = new Object[] {"/", 2, 1};
+ Object[] actual = division(literal(2), literal(1)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testDivisionLiteral() throws Exception {
+ Object[] expected = new Object[] {"/", 2, 1};
+ Object[] actual = division(2, 1).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testDivisionWithNestedGet() throws Exception {
+ Object nestedGet = new Object[] {"get", "key"};
+ Object[] expected = new Object[] {"/", 2, nestedGet};
+ Object[] actual = division(literal(2), get(literal("key"))).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testMod() throws Exception {
+ Object[] expected = new Object[] {"%", 1, 3};
+ Object[] actual = mod(literal(1), literal(3)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testModLiteral() throws Exception {
+ Object[] expected = new Object[] {"%", 1, 3};
+ Object[] actual = mod(1, 3).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testPow() throws Exception {
+ Object[] expected = new Object[] {"^", 2, 3};
+ Object[] actual = pow(literal(2), literal(3)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testPowLiteral() throws Exception {
+ Object[] expected = new Object[] {"^", 2, 3};
+ Object[] actual = pow(2, 3).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testSqrt() throws Exception {
+ Object[] expected = new Object[] {"sqrt", 4};
+ Object[] actual = sqrt(literal(4)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testSqrtLiteral() throws Exception {
+ Object[] expected = new Object[] {"sqrt", 4};
+ Object[] actual = sqrt(4).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testLog10() throws Exception {
+ Object[] expected = new Object[] {"log10", 10};
+ Object[] actual = log10(literal(10)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testLog10Literal() throws Exception {
+ Object[] expected = new Object[] {"log10", 10};
+ Object[] actual = log10(10).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testLn() throws Exception {
+ Object[] expected = new Object[] {"ln", 2};
+ Object[] actual = ln(literal(2)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testLnLiteral() throws Exception {
+ Object[] expected = new Object[] {"ln", 2};
+ Object[] actual = ln(2).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testLog2() throws Exception {
+ Object[] expected = new Object[] {"log2", 16};
+ Object[] actual = log2(literal(16)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testLog2Literal() throws Exception {
+ Object[] expected = new Object[] {"log2", 16};
+ Object[] actual = log2(16).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testSin() throws Exception {
+ Object[] expected = new Object[] {"sin", 45};
+ Object[] actual = sin(literal(45)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testSinLiteral() throws Exception {
+ Object[] expected = new Object[] {"sin", 45};
+ Object[] actual = sin(45).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testCos() throws Exception {
+ Object[] expected = new Object[] {"cos", 45};
+ Object[] actual = cos(literal(45)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testCosLiteral() throws Exception {
+ Object[] expected = new Object[] {"cos", 45};
+ Object[] actual = cos(45).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testTan() throws Exception {
+ Object[] expected = new Object[] {"tan", 45};
+ Object[] actual = tan(literal(45)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testTanLiteral() throws Exception {
+ Object[] expected = new Object[] {"tan", 45};
+ Object[] actual = tan(45).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testAsin() throws Exception {
+ Object[] expected = new Object[] {"asin", 45};
+ Object[] actual = asin(literal(45)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testAsinLiteral() throws Exception {
+ Object[] expected = new Object[] {"asin", 45};
+ Object[] actual = asin(45).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testAcos() throws Exception {
+ Object[] expected = new Object[] {"acos", 45};
+ Object[] actual = acos(literal(45)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testAcosLiteral() throws Exception {
+ Object[] expected = new Object[] {"acos", 45};
+ Object[] actual = acos(45).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testAtan() throws Exception {
+ Object[] expected = new Object[] {"atan", 45};
+ Object[] actual = atan(literal(45)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testAtanLiteral() throws Exception {
+ Object[] expected = new Object[] {"atan", 45};
+ Object[] actual = atan(45).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testMin() throws Exception {
+ Object[] expected = new Object[] {"min", 0, 1, 2, 3};
+ Object[] actual = min(literal(0), literal(1), literal(2), literal(3)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testMinLiteral() throws Exception {
+ Object[] expected = new Object[] {"min", 0, 1, 2, 3};
+ Object[] actual = min(0, 1, 2, 3).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testMax() throws Exception {
+ Object[] expected = new Object[] {"max", 0, 1, 2, 3};
+ Object[] actual = max(literal(0), literal(1), literal(2), literal(3)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testMaxLiteral() throws Exception {
+ Object[] expected = new Object[] {"max", 0, 1, 2, 3};
+ Object[] actual = max(0, 1, 2, 3).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testUpcase() throws Exception {
+ Object[] expected = new Object[] {"upcase", "string"};
+ Object[] actual = upcase(literal("string")).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testUpcaseLiteral() throws Exception {
+ Object[] expected = new Object[] {"upcase", "string"};
+ Object[] actual = upcase("string").toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testDowncase() throws Exception {
+ Object[] expected = new Object[] {"downcase", "string"};
+ Object[] actual = downcase(literal("string")).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testDowncaseLiteral() throws Exception {
+ Object[] expected = new Object[] {"downcase", "string"};
+ Object[] actual = downcase("string").toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testConcat() throws Exception {
+ Object[] expected = new Object[] {"concat", "foo", "bar"};
+ Object[] actual = concat(literal("foo"), literal("bar")).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testConcatLiteral() throws Exception {
+ Object[] expected = new Object[] {"concat", "foo", "bar"};
+ Object[] actual = concat("foo", "bar").toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testArray() throws Exception {
+ Object[] get = new Object[] {"get", "keyToArray"};
+ Object[] expected = new Object[] {"array", get};
+ Object[] actual = array(get(literal("keyToArray"))).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testArrayLiteral() throws Exception {
+ Object[] get = new Object[] {"get", "keyToArray"};
+ Object[] expected = new Object[] {"array", get};
+ Object[] actual = array(get("keyToArray")).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testTypeOf() throws Exception {
+ Object[] expected = new Object[] {"typeof", "value"};
+ Object[] actual = typeOf(literal("value")).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testString() throws Exception {
+ Object[] expected = new Object[] {"string", "value"};
+ Object[] actual = string(literal("value")).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testNumber() throws Exception {
+ Object[] expected = new Object[] {"number", 1};
+ Object[] actual = number(literal(1)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testBool() throws Exception {
+ Object[] expected = new Object[] {"boolean", true};
+ Object[] actual = bool(literal(true)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testObject() throws Exception {
+ Object object = new Object();
+ Object[] expected = new Object[] {"object", object};
+ Object[] actual = object(literal(object)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testToString() throws Exception {
+ Object[] expected = new Object[] {"to-string", 3};
+ Object[] actual = Expression.toString(literal(3)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testToNumber() throws Exception {
+ Object[] expected = new Object[] {"to-number", "3"};
+ Object[] actual = toNumber(literal("3")).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testToBool() throws Exception {
+ Object[] expected = new Object[] {"to-boolean", "true"};
+ Object[] actual = toBool(literal("true")).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testToColor() throws Exception {
+ Object[] expected = new Object[] {"to-color", "value"};
+ Object[] actual = toColor(literal("value")).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testLet() throws Exception {
+ Object[] expected = new Object[] {"let", "letName", "value"};
+ Object[] actual = let(literal("letName"), literal("value")).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testVar() throws Exception {
+ Object[] expected = new Object[] {"var", "letName"};
+ Object[] actual = var(literal("letName")).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testVarLiteral() throws Exception {
+ Object[] expected = new Object[] {"var", "letName"};
+ Object[] actual = var("letName").toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testVarExpression() throws Exception {
+ Object[] expected = new Object[] {"var", new Object[] {"get", "letName"}};
+ Object[] actual = var(get(literal("letName"))).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testVarExpressionLiteral() throws Exception {
+ Object[] expected = new Object[] {"var", new Object[] {"get", "letName"}};
+ Object[] actual = var(get("letName")).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testZoom() throws Exception {
+ Object[] expected = new Object[] {"zoom"};
+ Object[] actual = zoom().toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testStepBasic() throws Exception {
+ Object[] expected = new Object[] {"step", 12, 11, 0, 111, 1, 1111};
+ Object[] actual = step(literal(12), literal(11), literal(0), literal(111), literal(1), literal(1111)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testStepBasicLiteral() throws Exception {
+ Object[] expected = new Object[] {"step", new Object[] {"get", "line-width"}, 11, 0, 111, 1, 1111};
+ Object[] actual = step(get("line-width"), literal(11), stop(0, 111), stop(1, 1111)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testStepExpression() throws Exception {
+ Object[] input = new Object[] {"get", "key"};
+ Object[] number = new Object[] {"to-number", input};
+ Object[] expected = new Object[] {"step", number, 11, 0, 111, 1, 1111};
+ Object[] actual = step(toNumber(get(literal("key"))),
+ literal(11), literal(0), literal(111), literal(1), literal(1111)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testStepExpressionLiteral() throws Exception {
+ Object[] input = new Object[] {"get", "key"};
+ Object[] number = new Object[] {"to-number", input};
+ Object[] expected = new Object[] {"step", number, 11, 0, 111, 1, 1111};
+ Object[] actual = step(toNumber(get("key")), literal(11), stop(0, 111), stop(1, 1111)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testLinear() throws Exception {
+ Object[] stopZero = new Object[] {0, 1};
+ Object[] stopOne = new Object[] {1, 2};
+ Object[] stopTwo = new Object[] {2, 3};
+ Object[] expected = new Object[] {"interpolate", new Object[] {"linear"}, 12, stopZero, stopOne, stopTwo};
+ Object[] actual = interpolate(linear(), literal(12),
+ literal(stopZero), literal(stopOne), literal(stopTwo)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testLinearStops() throws Exception {
+ Object[] expected = new Object[] {"interpolate", new Object[] {"linear"}, 12, 0, 1, 1, 2, 2, 3};
+ Object[] actual = interpolate(linear(), literal(12), stop(0, 1), stop(1, 2), stop(2, 3)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testExponential() throws Exception {
+ Object[] exponential = new Object[] {"exponential", 12};
+ Object[] get = new Object[] {"get", "x"};
+ Object[] expected = new Object[] {"interpolate", exponential, get, 0, 100, 200};
+ Object[] actual = interpolate(exponential(literal(12)),
+ get(literal("x")), literal(0), literal(100), literal(200)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testExponentialLiteral() throws Exception {
+ Object[] exponential = new Object[] {"exponential", 12};
+ Object[] get = new Object[] {"get", "x"};
+ Object[] expected = new Object[] {"interpolate", exponential, get, 0, 100, 100, 200};
+ Object[] actual = interpolate(exponential(12), get("x"), stop(0, 100), stop(100, 200)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testExponentialExpressionLiteral() throws Exception {
+ Object[] getX = new Object[] {"get", "x"};
+ Object[] exponential = new Object[] {"exponential", getX};
+ Object[] getY = new Object[] {"get", "y"};
+ Object[] expected = new Object[] {"interpolate", exponential, getY, 0, 100, 100, 200};
+ Object[] actual = interpolate(exponential(get("x")), get("y"), stop(0, 100), stop(100, 200)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testCubicBezier() throws Exception {
+ Object[] cubicBezier = new Object[] {"cubic-bezier", 1, 1, 1, 1};
+ Object[] get = new Object[] {"get", "x"};
+ Object[] expected = new Object[] {"interpolate", cubicBezier, get, 0, 100, 100, 200};
+ Object[] actual = interpolate(cubicBezier(literal(1), literal(1), literal(1), literal(1)),
+ get(literal("x")), literal(0), literal(100), literal(100), literal(200)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testCubicBezierLiteral() throws Exception {
+ Object[] cubicBezier = new Object[] {"cubic-bezier", 1, 1, 1, 1};
+ Object[] get = new Object[] {"get", "x"};
+ Object[] expected = new Object[] {"interpolate", cubicBezier, get, 0, 100, 100, 200};
+ Object[] actual = interpolate(cubicBezier(1, 1, 1, 1), get("x"), stop(0, 100), stop(100, 200)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testCubicBezierExpression() throws Exception {
+ Object[] getX = new Object[] {"get", "x"};
+ Object[] getY = new Object[] {"get", "y"};
+ Object[] getZ = new Object[] {"get", "z"};
+ Object[] cubicBezier = new Object[] {"cubic-bezier", getZ, 1, getY, 1};
+ Object[] expected = new Object[] {"interpolate", cubicBezier, getX, 0, 100, 200};
+ Object[] actual = interpolate(cubicBezier(get(literal("z")), literal(1),
+ get(literal("y")), literal(1)), get(literal("x")), literal(0), literal(100), literal(200)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+
+ @Test
+ public void testCubicBezierExpressionLiteral() throws Exception {
+ Object[] getX = new Object[] {"get", "x"};
+ Object[] getY = new Object[] {"get", "y"};
+ Object[] getZ = new Object[] {"get", "z"};
+ Object[] cubicBezier = new Object[] {"cubic-bezier", getZ, 1, getY, 1};
+ Object[] expected = new Object[] {"interpolate", cubicBezier, getX, 0, 100, 100, 200};
+ Object[] actual = interpolate(cubicBezier(get("z"), literal(1), get("y"),
+ literal(1)), get("x"), stop(0, 100), stop(100, 200)).toArray();
+ assertTrue("expression should match", Arrays.deepEquals(expected, actual));
+ }
+} \ No newline at end of file